Init
This commit is contained in:
19
07-Other/Qt/QGraphics系列笔记.md
Normal file
19
07-Other/Qt/QGraphics系列笔记.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 坐标
|
||||
1. Item(图元)坐标:属于局部坐标,通常以图元中心为原点(中心对称),非中心对称类,比如dialog类,一般以左上角为原点,正方向x朝右,y朝下。
|
||||
2. setPos的坐标是父类坐标系的坐标,一般对于item位于scene中的应用场景。
|
||||
3. scene(场景)坐标:属于逻辑坐标 logical coordinates(与QPainter相同),**以场景中心为原点**,正方向x朝右,y朝下。
|
||||
4. 图元原点(左上角dialog的原点)**与场景原点对齐**,导致图元外边框的左上角顶点在场景中的坐标位置为(负数,负数)。
|
||||
5. View(视图)坐标:属于设备坐标device coordinates(与窗口相同),**默认以左上点为原点**, 正方向x朝右,y朝下。
|
||||
6. 默认场景scene的左上角顶点与视图坐标原点对齐。**显示时默认中心对齐**,当场景大小小于视图大小的时候,将中心对齐,此中指的仍然是整个图元的中心,同时,图元原点与场景原点对齐,场景左上角顶点与视图原点对齐,视图左上角顶点不一定是原点???,此时也将出现视图坐标有正值有负值。
|
||||
|
||||
- 1)translate()将当前视图坐标原点平移,从而实现显示图像的平移变换。由于默认场景的左上角顶点与视图坐标原点对齐,translate()将坐标原点平移,也就实现了将场景的平移。
|
||||
- 2)rotate()将当前视图围绕视图坐标原点旋转,从而实现显示图像的旋转变换。
|
||||
- 3)size()返回视图大小,默认大小100*30,由于视图可以是无限大小而且只有在显示后才创建出实际尺寸,因此只有在showEvent中调用 size 函数才能正确显示视图大小,否则都是返回默认的100*30,因为此时视图尚未显示,即尚未形成。
|
||||
|
||||
https://www.cnblogs.com/cthu/p/5103551.html
|
||||
|
||||
## 常用的QGraphicsItem
|
||||
https://blog.csdn.net/liang19890820/article/details/53065293
|
||||
|
||||
## QGraphics
|
||||
https://blog.csdn.net/liang19890820/article/details/51966791
|
79
07-Other/Qt/Qt On Android 隐藏状态栏的方法.md
Normal file
79
07-Other/Qt/Qt On Android 隐藏状态栏的方法.md
Normal file
@@ -0,0 +1,79 @@
|
||||
## 注意点
|
||||
隐藏状态栏时,第一个界面不能使用Qt设计师界面类(创建项目时,不勾选**创建界面**选项)。不然以下方法皆会无效。
|
||||
|
||||
## 方法1
|
||||
修改AndroidManifest.xml中activity的主题。即在`<activity>`标签中添加 `android:theme="@android:style/Theme.NoTitleBar.Fullscreen"`
|
||||
|
||||
以下为实例代码:
|
||||
```
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||
android:name="an.qt.helloQtQuickApp.QtFullscreenActivity"
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:screenOrientation="unspecified"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:launchMode="singleTop">
|
||||
```
|
||||
如果无效,则需要重写QtActivity的onCreate函数。
|
||||
大致步骤如下:
|
||||
1. 在项目目录\android\src\目录下创建与包名相同的目录。例如:我们要创建的包为an.qt.helloQtQuickApp,那么路径为an\qt\helloQtQuickApp。并创建一个Java文件,用于定义我们的Activity。文件名可以随便取,我这里的文件名设为QtFullscreenActivity.java。
|
||||
2. 修改AndroidManifest.xml文件,使用我们刚才新定义的Activity。
|
||||
将` <manifest>` 标签中的package改成我们创建的包名。将`<activity>`标签中android:name改成an.qt.helloQtQuickApp.QtFullscreenActivity,即包名.新创建的Activity类名。
|
||||
>Java文件代码如下:
|
||||
```
|
||||
package an.qt.helloQtQuickApp;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.app.PendingIntent;
|
||||
import android.util.Log;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class QtFullscreenActivity extends org.qtproject.qt5.android.bindings.QtActivity
|
||||
{
|
||||
private final static String TAG = "QtFullscreen";
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
详细操作过程可以参看安晓辉的blog:
|
||||
https://blog.csdn.net/foruok/article/details/38265349
|
||||
|
||||
## 方法2
|
||||
大致思路如下:使用Qt5.7后,在QtAndroid类新增了一个静态函数:
|
||||
```
|
||||
void QtAndroid::runOnAndroidThread(const QtAndroid::Runnable &runnable)
|
||||
```
|
||||
通过它调用以下Java代码:
|
||||
```
|
||||
Activity activity = (Activity) mContext;
|
||||
View decorView = activity.getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN);
|
||||
```
|
||||
这种方法的好处在于,可以在运行时控制是否隐藏状态栏,而且不用改AndroidManifest.xml文件,移植方便。
|
||||
|
||||
详细操作可以见作者Blog:
|
||||
https://blog.csdn.net/jun4331247/article/details/80739662
|
||||
|
||||
项目Github:
|
||||
https://github.com/WingNan/QtAndroidFullScreen
|
||||
|
||||
### 移植步骤
|
||||
1. 复制文件jfullscreen.h、jfullscreen.cpp至你的项目目录。复制android/src目录及其内部文件至项目同名目录。
|
||||
2. 在项目上右键点击“添加现有文件",将以上几个文件添加到项目中。
|
||||
3. 编辑项目文件(*.pro),添加androidextras模块(在Qt+=core gui后面加上androidextras)
|
||||
4. 在app的第一个widget中#include "jfullscreen.h",并在构造函数中加入:
|
||||
```
|
||||
JFullScreen *pManager = new JFullScreen;
|
||||
pManager->fullScreenStickyImmersive();
|
||||
```
|
||||
注意:创建项目时不能勾选“创建界面”选项,并且第一个widget不能使用设计师界面类来创建!
|
53
07-Other/Qt/QtGUI/IconFont.md
Normal file
53
07-Other/Qt/QtGUI/IconFont.md
Normal file
@@ -0,0 +1,53 @@
|
||||
## 字体文件下载
|
||||
fontawesome-webfont.ttf,另一个是:pe-icon-set-weather.ttf
|
||||
fontawesome-webfont.ttf 下载地址:http://fontawesome.dashgame.com/
|
||||
pe-icon-set-weather.ttf 下载地址:https://www.pixeden.com/icon-fonts/the-icons-font-set-weather
|
||||
在pixeden中还有许多其它的图标字体库下载:https://www.pixeden.com/icon-fonts
|
||||
|
||||
## Code
|
||||
```
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include <QFontDatabase>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
//引入图形字体
|
||||
int fontId = QFontDatabase::addApplicationFont(":/image/pe-icon-set-weather.ttf"); //加入字体,并获取字体ID
|
||||
QString fontName = QFontDatabase::applicationFontFamilies(fontId).at(0); //获取字体名称
|
||||
QFont iconFont = QFont(fontName);
|
||||
iconFont.setPixelSize(128); //设置字体大小
|
||||
|
||||
ui->lab_e901->setFont(iconFont); //设置Label的字体
|
||||
ui->lab_e901->setText(QChar(0xe901)); //设置Label的文体
|
||||
ui->lab_e901->setStyleSheet("color:red;");
|
||||
|
||||
QPalette blue_pe;
|
||||
blue_pe.setColor(QPalette::WindowText,Qt::blue);
|
||||
ui->lab_e903->setFont(iconFont);
|
||||
ui->lab_e903->setText(QChar(0xe903));
|
||||
ui->lab_e903->setPalette(blue_pe);
|
||||
|
||||
ui->lab_e905->setFont(iconFont);
|
||||
ui->lab_e905->setText(QChar(0xe905));
|
||||
|
||||
ui->lab_e907->setFont(iconFont);
|
||||
ui->lab_e907->setText(QChar(0xe907));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
```
|
||||
|
||||
## QFontDatabase
|
||||
QStringList QFontDatabase::families(QFontDatabase::WritingSystem writingSystem = Any) const
|
||||
返回可用的字体列表。
|
||||
|
||||
QFont QFontDatabase::font(const QString &family, const QString &style, int pointSize) const
|
||||
返回一个可用的字体对象。
|
104
07-Other/Qt/QtGUI/QSS笔记.md
Normal file
104
07-Other/Qt/QtGUI/QSS笔记.md
Normal file
@@ -0,0 +1,104 @@
|
||||
## 通用选择器
|
||||
* 作为选择器,作用于所有的 widget。
|
||||
|
||||
类型选择器
|
||||
类名 作为选择器,作用于它自己和它的所有子类。
|
||||
```
|
||||
QFrame {
|
||||
background: gray;
|
||||
}
|
||||
```
|
||||
|
||||
## 类选择器
|
||||
. + 类名 或者 . + class 的属性值 作为选择器(使用 setProperty(“class”, “QSSClassName”) 设置),只会作用于它自己,它的子类不受影响,注意和类型选择器的区别。
|
||||
```
|
||||
app.setStyleSheet(".QWidget { background: gray; }"
|
||||
".RedButton { background: magenta; }");
|
||||
|
||||
// .RedButton 将作为类选择器
|
||||
openButton->setProperty("class", "RedButton");
|
||||
closeButton->setProperty("class", "RedButton");
|
||||
```
|
||||
|
||||
## ID 选择器
|
||||
'#' + objectName 作为选择器,只作用于用此 objectName 的对象
|
||||
```
|
||||
// #openButton 和 #closeButton 作为 ID 选择器
|
||||
app.setStyleSheet(".QWidget { background: gray; }"
|
||||
"#openButton, #closeButton { background: magenta; }");
|
||||
|
||||
openButton->setObjectName("openButton");
|
||||
closeButton->setObjectName("closeButton");
|
||||
```
|
||||
## 属性选择器
|
||||
选择器[属性="值"] 作为选择器,这个属性可用通过 object->property(propertyName) 访问的,Qt 里称为 Dynamic Properties。
|
||||
|
||||
如上面的程序, openButton 和 closeButton 的背景是洋红色的,但是 saveButton 不受影响,也可以使用属性选择器来实现:
|
||||
```
|
||||
app.setStyleSheet(".QWidget { background: gray; }"
|
||||
"QPushButton[level='dangerous'] { background: magenta; }");
|
||||
|
||||
openButton->setProperty("level", "dangerous");
|
||||
```
|
||||
|
||||
属性选择器可以包含多个属性,只需要:
|
||||
```
|
||||
QPushButton[level='aaa'],QPushButton[level='bbb'] { background: magenta; }
|
||||
```
|
||||
如果有多个属性,则会优先选择匹配数多的样式。
|
||||
|
||||
## 包含选择器
|
||||
英语叫做 Descendant Selector,descendant 的表达比较到位。
|
||||
|
||||
选择器之间用空格隔开,作用于 Widget 的 子Widget,子Widget 的 子Widget,……,子子孙孙,无穷尽也。
|
||||
```
|
||||
QFrame {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
/* 设置 QFrame 中的 QPushButton 的 QSS */
|
||||
QFrame QPushButton {
|
||||
border: 2px solid magenta;
|
||||
border-radius: 10px;
|
||||
background: white;
|
||||
padding: 2px 15px;
|
||||
}
|
||||
```
|
||||
|
||||
## 子元素选择器
|
||||
选择器之间用 > 隔开,作用于 Widget 的直接 子Widget,注意和包含选择器的区别。
|
||||
```
|
||||
QFrame {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
QFrame > QPushButton {
|
||||
border: 2px solid magenta;
|
||||
border-radius: 10px;
|
||||
background: white;
|
||||
padding: 2px 15px;
|
||||
}
|
||||
```
|
||||
|
||||
## 伪类选择器
|
||||
选择器:状态 作为选择器,支持 ! 操作符,表示 非。
|
||||
```
|
||||
QPushButton:hover { color: white }
|
||||
QCheckBox:checked { color: white }
|
||||
QCheckBox:!checked { color: red }
|
||||
```
|
||||
|
||||
## Subcontrol 选择器
|
||||
选择器::subcontrol 作为选择 Subcontrol 的选择器。
|
||||
|
||||
有些 widget 是由多个部分组合成的,例如 QCheckBox 由 icon(indicator) 和 text 组成,可以使用 选择器::subcontrol 来设置 subcontrol 的样式:
|
||||
```
|
||||
QCheckBox::indicator {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
QCheckBox {
|
||||
spacing: 8px;
|
||||
}
|
||||
```
|
102
07-Other/Qt/QtGUI/QtUI方案.md
Normal file
102
07-Other/Qt/QtGUI/QtUI方案.md
Normal file
@@ -0,0 +1,102 @@
|
||||
## 参考项目
|
||||
https://blog.csdn.net/liang19890820/article/details/50557240
|
||||
https://www.cnblogs.com/feiyangqingyun/p/3915657.html
|
||||
|
||||
QSS模板网站:https://qss-stock.devsecstudio.com/
|
||||
|
||||
## 技巧
|
||||
Qt内置图标封装在QStyle中,大概七十多个图标,可以直接拿来用。
|
||||
|
||||
- SP_TitleBarMenuButton,
|
||||
- SP_TitleBarMinButton,
|
||||
- SP_TitleBarMaxButton,
|
||||
- SP_TitleBarCloseButton,
|
||||
- SP_MessageBoxInformation,
|
||||
- SP_MessageBoxWarning,
|
||||
- SP_MessageBoxCritical,
|
||||
- SP_MessageBoxQuestion,
|
||||
|
||||
## 配色
|
||||
ElementUI配色:https://element.eleme.cn/#/zh-CN/component/color
|
||||
|
||||
Brand Color `#409EFF`
|
||||
|
||||
**辅助色**:
|
||||
- Success#67C23A
|
||||
- Warning#E6A23C
|
||||
- Danger#F56C6C
|
||||
- Info#909399
|
||||
|
||||
**基础色**:
|
||||
- 主要文字#303133
|
||||
- 常规文字#606266
|
||||
- 次要文字#909399
|
||||
- 占位文字#C0C4CC
|
||||
- 一级边框#DCDFE6
|
||||
- 二级边框#E4E7ED
|
||||
- 三级边框#EBEEF5
|
||||
- 四级边框#F2F6FC
|
||||
|
||||
## 边框
|
||||
- 实线 1px
|
||||
- 虚线 2px
|
||||
|
||||
### 圆角
|
||||
- 无圆角border-radius: 0px
|
||||
- 小圆角border-radius: 2px
|
||||
- 大圆角border-radius: 4px
|
||||
- 圆形圆角border-radius: 30px
|
||||
|
||||
### 投影
|
||||
- 基础投影 box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)
|
||||
- 浅色投影 box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)
|
||||
|
||||
## QSS设置函数
|
||||
feiyangqingyun-QWidgetDemo-master/FlatUI<br>
|
||||
使用函数的方式来生成QSS代码与设置对应的控件。
|
||||
```
|
||||
QString BRUI::setPushButtonQss(QPushButton *btn, int radius, int padding,const QString &normalColor,const QString &normalTextColor,const QString &hoverColor,const QString &hoverTextColor,const QString &pressedColor,const QString &pressedTextColor)
|
||||
{
|
||||
QStringList list;
|
||||
list.append(QString("QPushButton{border-style:none;padding:%1px;border-radius:%2px;color:%3;background:%4;}").arg(padding).arg(radius).arg(normalTextColor).arg(normalColor));
|
||||
list.append(QString("QPushButton:hover{color:%1;background:%2;}").arg(hoverTextColor).arg(hoverColor));
|
||||
list.append(QString("QPushButton:pressed{color:%1;background:%2;}").arg(pressedTextColor).arg(pressedColor));
|
||||
|
||||
QString qss = list.join("");
|
||||
if(btn)
|
||||
btn->setStyleSheet(qss);
|
||||
return qss;
|
||||
}
|
||||
```
|
||||
## 可以参考的UI工程
|
||||
QSS生成工具:StyleDemo。
|
||||
|
||||
给QWidget添加属性来控制样式:
|
||||
```
|
||||
ui->widgetLeft->setProperty("nav", "left");
|
||||
ui->widgetBottom->setProperty("form", "bottom");
|
||||
ui->widgetTop->setProperty("nav", "top");
|
||||
ui->widgetVideo->setProperty("video", true);
|
||||
```
|
||||
Qss:
|
||||
```
|
||||
QWidget[nav="left"] QAbstractButton:checked,QWidget[nav="left"] QAbstractButton:pressed{
|
||||
color:#386487;
|
||||
border-style:solid;
|
||||
border-width:0px 0px 0px 2px;
|
||||
padding:4px 4px 4px 2px;
|
||||
border-color:#00BB9E;
|
||||
background-color:#EAF7FF;
|
||||
}
|
||||
```
|
||||
### 切换器
|
||||
ImageSwitch
|
||||
### 日历
|
||||
lunarcalendarwidget
|
||||
### 导航按钮
|
||||
NavButton
|
||||
|
||||
## StyleDemo中的CSS
|
||||
flatwhite.css
|
||||
lightblue.css
|
||||
psblack.css
|
121
07-Other/Qt/QtQuick/QtQuick中QML文件间的通讯问题.md
Normal file
121
07-Other/Qt/QtQuick/QtQuick中QML文件间的通讯问题.md
Normal file
@@ -0,0 +1,121 @@
|
||||
## 前言
|
||||
本人发现有关QML文件之间的通讯的资料不多,而且都不太好找,所以在这里总结一下方便后续的开发者
|
||||
|
||||
## 直接导入qml
|
||||
目录结构:
|
||||
```
|
||||
myapp
|
||||
|- mycomponents
|
||||
|- CheckBox.qml
|
||||
|- DialogBox.qml
|
||||
|- Slider.qml
|
||||
|- main
|
||||
|- application.qml
|
||||
```
|
||||
那么可以:
|
||||
```
|
||||
import "../mycomponents"
|
||||
|
||||
DialogBox {
|
||||
CheckBox {
|
||||
// ...
|
||||
}
|
||||
Slider {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
但是创建一个命名空间来导入会更好
|
||||
```
|
||||
import "../mycomponents" as MyComponents
|
||||
|
||||
MyComponents.DialogBox {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## qml文件间通讯
|
||||
3.题回正传,直接上代码(以StackView管理页面为例)
|
||||
(1)page1.qml跳转到page2.qml传值
|
||||
```
|
||||
page1.qml
|
||||
|
||||
Rectangle
|
||||
{
|
||||
id:rect1
|
||||
...
|
||||
MouseArea {
|
||||
id: maStartQuery
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
if(!stackView.busy)
|
||||
stackView.push(Qt.resolvedUrl("qrc:///qml/page2.qml"),
|
||||
{name:"张三"})//给page2.qml的name传值“张三”,name必须在page2.qml中定义成属性
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
page2.qml定义如下
|
||||
|
||||
Rectangle
|
||||
{
|
||||
id:rect2
|
||||
...
|
||||
property string name:""//要传的值
|
||||
...
|
||||
|
||||
}
|
||||
```
|
||||
(2)page2.qml点击"确定"按钮时将结果返回给page1.qml
|
||||
|
||||
A.在page1.qml中增加一个函数clickedfunc,当点击page2.qml中"确定"按钮时调用;
|
||||
B.在page2.qml中增加一个属性containerqml,用来记录page1.qml;
|
||||
C.在从page1.qml跳转到page2.qml时,将rect1传给page2.qml的containerqml属性。
|
||||
```
|
||||
page1.qml
|
||||
Rectangle
|
||||
{
|
||||
id:rect1
|
||||
...
|
||||
MouseArea {
|
||||
id: maStartQuery
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
if(!stackView.busy)
|
||||
stackView.push(Qt.resolvedUrl("qrc:///qml/page2.qml"),
|
||||
{name:"张三",containerqml:rect1})
|
||||
}
|
||||
}
|
||||
|
||||
//当点击page2.qml中"确定"按钮时调用
|
||||
function clickedfunc(temp)
|
||||
{
|
||||
console.log("改成了:"+temp);
|
||||
stackView.pop();//返回到本页
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
page2.qml
|
||||
Rectangle
|
||||
{
|
||||
id:rect2
|
||||
...
|
||||
property variant containerqml: null
|
||||
property string name:""//要传的值
|
||||
...
|
||||
MouseArea {
|
||||
id: btnOK
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
containerqml.clickedfunc("李四");//调用page1.qml中的函数,实现了传返回值。
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
另一种就是信号与槽
|
163
07-Other/Qt/QtQuick/QtQuick基础笔记.md
Normal file
163
07-Other/Qt/QtQuick/QtQuick基础笔记.md
Normal file
@@ -0,0 +1,163 @@
|
||||
## color属性
|
||||
可以使用"blue"、"#RRGGBB"、Qt.rgba()来赋值。具体可以参考QML Basic Type:color
|
||||
|
||||
## 手机的横屏模式与竖屏模式
|
||||
需要修改AndroidManifest.xml中的activity元素的android:screenOrientation属性为"landscape"或"portrait"
|
||||
## Item组件
|
||||
1. Item是所有可视元素的基类。
|
||||
2. 其中一个用处就是可以分组其他可见图元。
|
||||
3. clip属性如果为true可以裁剪子组件。
|
||||
4. 通过附加属性Keys来处理按键。详情:Keys QML Type
|
||||
|
||||
## Text
|
||||
可以使用HTML修饰过的文本
|
||||
|
||||
## Image
|
||||
1. 如何设置了width与height,图片可能会被拉伸,此时fillMode属性就可以设置填充模式了。
|
||||
2. Image默认是阻塞式加载,可以通过把asynchronous设为true开启异步模式。可以先显示一个加载图标,当status的值为Image.Ready时再显示。
|
||||
3. source属性是url,网络模式会默认开启异步加载,此时Image的Progress(0。0~1.0)、status都会实时更新。
|
||||
```
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
ApplicationWindow {
|
||||
visible: true
|
||||
width: 640
|
||||
height: 480
|
||||
title: qsTr("App")
|
||||
|
||||
BusyIndicator{
|
||||
id:busy;
|
||||
running: true;
|
||||
anchors.centerIn: parent;
|
||||
z:2
|
||||
}
|
||||
|
||||
Text{
|
||||
id:stateLabel;
|
||||
visible:false;
|
||||
anchors.centerIn: parent;
|
||||
z:3
|
||||
}
|
||||
|
||||
Image{
|
||||
id:imageViewer;
|
||||
asynchronous: true;
|
||||
cache:false;
|
||||
anchors.fill: parent;
|
||||
fillMode: Image.PreserveAspectFit;
|
||||
onStatusChanged: {
|
||||
if(imageViewer.status===Image.Loading){
|
||||
busy.running=true;
|
||||
stateLabel.visible=false;
|
||||
}else if (imageViewer.status===Image.Ready){
|
||||
busy.running=false;
|
||||
}else if(imageViewer.status===Image.Error){
|
||||
busy.running=false;
|
||||
stateLabel.visible=true;
|
||||
stateLabel.text="error";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
imageViewer.source="http://img.zcool.cn/community/01d881579dc3620000018c1b430c4b.JPG@3000w_1l_2o_100sh.jpg";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Object类是所有ECMAScript类的基类,它具有以下属性:
|
||||
1. constructor:指向创建对象的函数,对于Object类,它指向object()函数。
|
||||
2. prototype:对该对象原型类型的引用,可以在运行时改变原型。
|
||||
3. hasOwnPropety:是否拥有某个属性
|
||||
4. isPrototypeOf:判断对象是否为另一个对象的原型。
|
||||
5. ptopertyIsEnumerable:判断给定的杏树是否可以用for in进行枚举。
|
||||
6. toString()
|
||||
7. valueOf(),返回最适合该对象的原始值。
|
||||
|
||||
## Qt对象
|
||||
Qt是QML提供的一个全局宿主对象,整合了常用的属性、方法与枚举类型。
|
||||
Qt.application 应用的全局状态
|
||||
## Connections
|
||||
适用对象:
|
||||
1. 你需要将多个对象连接到同一个QML信号上。
|
||||
2. 你需要在发出信号的对象的作用域之外来建立连接
|
||||
3. c++导出对象
|
||||
```
|
||||
Connections{
|
||||
target:area;//目标控件(它的信号触发)
|
||||
on<Signal>:function or code block;//执行代码
|
||||
}
|
||||
```
|
||||
|
||||
## 连接信号的方式
|
||||
```
|
||||
Rectangle {
|
||||
id: relay
|
||||
|
||||
signal messageReceived(string person, string notice)
|
||||
|
||||
//可以连接信号或者函数
|
||||
Component.onCompleted: {
|
||||
relay.messageReceived.connect(sendToPost)
|
||||
relay.messageReceived.connect(sendToTelegraph)
|
||||
relay.messageReceived.connect(sendToEmail)
|
||||
relay.messageReceived("Tom", "Happy Birthday")
|
||||
}
|
||||
|
||||
function sendToPost(person, notice) {
|
||||
console.log("Sending to post: " + person + ", " + notice)
|
||||
}
|
||||
function sendToTelegraph(person, notice) {
|
||||
console.log("Sending to telegraph: " + person + ", " + notice)
|
||||
}
|
||||
function sendToEmail(person, notice) {
|
||||
console.log("Sending to email: " + person + ", " + notice)
|
||||
}
|
||||
}
|
||||
```
|
||||
## component
|
||||
### 嵌入式组件:
|
||||
```
|
||||
Component {
|
||||
id: redSquare
|
||||
|
||||
Rectangle {
|
||||
color: "red"
|
||||
width: 10
|
||||
height: 10
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
只能包含一个顶层item与id<br>
|
||||
### 单文件组件
|
||||
单文件组件不需要加Component
|
||||
#### 使用Loader
|
||||
```
|
||||
Item {
|
||||
Component {
|
||||
id: redSquare
|
||||
Rectangle { color: "red"; width: 10; height: 10 }
|
||||
}
|
||||
|
||||
Loader { sourceComponent: redSquare }
|
||||
Loader { sourceComponent: redSquare; x: 10 }
|
||||
}
|
||||
```
|
||||
通过sourceComponent加载组件,source则可以通过url加载单文件组件。<br>
|
||||
在加载完成后(onLoaded)后可以通过Loader的item操作已经加载的组件<br>
|
||||
如果Loader加载的Item想要处理按键事件,那么久必须将Loader对象的focus属性设置为true,同时也需要对它加载的Item的accepted属性设置为true,以免已经被吃掉的事件再传递给Loader。
|
||||
### ECMAScript中动态创建对象
|
||||
```
|
||||
var newObject = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',
|
||||
parentItem,
|
||||
"dynamicSnippet1");
|
||||
```
|
||||
或者
|
||||
```
|
||||
var component = Qt.createComponent("Button.qml");
|
||||
if (component.status == Component.Ready)
|
||||
component.createObject(parent, {"x": 100, "y": 100});
|
||||
```
|
113
07-Other/Qt/QtQuick/QtQuick大坑笔记之Http的Get与Post操作(带cookie).md
Normal file
113
07-Other/Qt/QtQuick/QtQuick大坑笔记之Http的Get与Post操作(带cookie).md
Normal file
@@ -0,0 +1,113 @@
|
||||
## 前言
|
||||
最近在为单位做一个简单的手机App,基于Qt技术栈的选择了QtQuick来开发。不得不说QtQucik开发的确舒服,很多东西都不用写就可以只用,UI定义起来也比较自由。但是本人想通过cookie来作为登陆验证时就发现,QtQuick实现起来相当麻烦。(主要是没有文档,资料只找到一篇qyvlik写的。我也不想直接用WebEngine)
|
||||
|
||||
## 不带cookie
|
||||
可以使用XMLHttpRequest,比较坑的是官方竟然没有任何案例,不过Api都是与js的XmlHttpRequest一样的,以下是qyvlik封装的一套分辨操作函数:
|
||||
```
|
||||
//通过Json对象输出url的query字符串
|
||||
function urlQuery(jsonObject) {
|
||||
var query = "";
|
||||
var i = 0;
|
||||
for(var iter in jsonObject) {
|
||||
|
||||
if(i > 0) {
|
||||
query += "&";
|
||||
}
|
||||
query += iter +"=" + encodeURI(jsonObject[iter]);
|
||||
i++;
|
||||
}
|
||||
// console.log("url query:", query);
|
||||
return query;
|
||||
}
|
||||
//设置头
|
||||
function setHeader(xhr, headers) {
|
||||
//"Content-Type":"application/x-www-form-urlencoded"
|
||||
for(var iter in headers) {
|
||||
xhr.setRequestHeader(iter, headers[iter]);
|
||||
}
|
||||
}
|
||||
//这里我修改了一下函数的形参,从使用的角度来看,回调函数一般都会有,但是headers不一定要设置,所以调换了一下位置
|
||||
function ajax(method, url, callable,headers,data) {
|
||||
headers = headers || {};
|
||||
callable = callable || function(xhr) {
|
||||
console.log("没有设置callable,使用默认log函数")
|
||||
console.log(xhr.status);
|
||||
console.log(xhr.responseText);
|
||||
}
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState == xhr.DONE) {
|
||||
callable(xhr);
|
||||
}
|
||||
}
|
||||
xhr.open(method, url);
|
||||
setHeader(xhr, headers);
|
||||
if("GET" === method) {
|
||||
xhr.send();
|
||||
} else {
|
||||
xhr.send(data);
|
||||
}
|
||||
}
|
||||
```
|
||||
为了能够重复利用,本人将这些代码都放入一个js文件中,之后使用导入的方式重复利用。(注意:导入的命名控件首字母需要大写)
|
||||
```
|
||||
import "xmlhttprequest.js" as XmlHttpRequest
|
||||
```
|
||||
使用:
|
||||
```
|
||||
var jsonObject={user:"admin",password:Qt.md5("123")};
|
||||
|
||||
XmlHttpRequest.ajax("GET","http://192.168.3.108:3000/landing"+"?"+XmlHttpRequest.urlQuery(jsonObject),function(xhr){
|
||||
console.log(xhr.status);
|
||||
console.log(xhr.responseText);
|
||||
if(JSON.parse(xhr.responseText).message==="ok") {
|
||||
stack.push("qrc:/resource/qml/listview.qml",{stack:stack,uifont:uifont});
|
||||
}else{
|
||||
message.show("用户名或者密码错误!",2000);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 带cookie
|
||||
因为XmlHttpRequest是不能带有cookie的,所以只能通过c++导出QNetworkAccessManager、QNetworkRequest、QNetworkReply,具体的代码可以参考https://github.com/qyvlik/QmlNetwork。qyvlik封装了一套QML对象,我直接拿来用了,很可惜他的使用说明写的不太详细,有一些操作需要直接看他写的微信案例才能搞定。
|
||||
```
|
||||
NetworkAccessManager { id: manager }
|
||||
NetworkResponse { id: response }
|
||||
NetworkRequest { id: request }
|
||||
Buffer { id: buffer }
|
||||
|
||||
function initWebWeiXinInfo() {
|
||||
var url = "http://192.168.3.108:3000/landing";
|
||||
var data = {
|
||||
user:"admin",
|
||||
password:"123"
|
||||
};
|
||||
|
||||
if(buffer.isOpen()) {
|
||||
buffer.close();
|
||||
}
|
||||
buffer.data = JSON.stringify(data);
|
||||
if(!buffer.open(IODevice.ReadOnly)) {
|
||||
console.log(buffer.errorString());
|
||||
}
|
||||
request.clear();
|
||||
request.url = url;
|
||||
// request.setHeader("Cookie", cookie);
|
||||
request.setHeader("Content-Type", "application/json")
|
||||
request.ioDevice = buffer;
|
||||
|
||||
connectSignalOnce(response.finished,function() {
|
||||
console.log("data:", buffer.data)
|
||||
var headers = response.getAllResponseHeaders();
|
||||
for(var iter in headers) {
|
||||
console.log(headers[iter]);
|
||||
}
|
||||
console.log(response.responseContent);
|
||||
});
|
||||
|
||||
manager.post(request, response);
|
||||
}
|
||||
```
|
||||
|
||||
## 结语
|
||||
感觉qyvlik封装的东西比较多,需求上本人也就用用Get与Post以及cookie,以后有时间会重新封装一个简单版本。
|
118
07-Other/Qt/QtQuick/QtQuick自定义主题以及控件样式.md
Normal file
118
07-Other/Qt/QtQuick/QtQuick自定义主题以及控件样式.md
Normal file
@@ -0,0 +1,118 @@
|
||||
## 自定义控件样式
|
||||
请在Qt帮助索引中输入Customizing a Control进行查看<br>
|
||||
不过实际用下来感觉除非你想自己实现一套效果复杂的UI或是创造一个全新控件,比如:给UI添加模糊、虚化等ShaderEffect效果。不然不推荐用这个。比如本人就是想把CheckBox的大小改小,同时不改变显示样式,这个就很难办到。<br>
|
||||
## 系统自带的几种主题风格
|
||||
1. Default Style
|
||||
2. Fusion Style
|
||||
3. Imagine Style
|
||||
4. Material Style
|
||||
5. Universal Style
|
||||
其中Imagine Style是使用图片定制风格,图片需要按照指定的命名来放置,具体操作请看文档:
|
||||
http://doc.qt.io/qt-5/qtquickcontrols2-imagine.html
|
||||
|
||||
### 在c++中使用QQuickStyle
|
||||
```
|
||||
QQuickStyle::setStyle("Material");
|
||||
```
|
||||
具体内容请在帮助索引中搜索 QQuickStyle
|
||||
### 命令行中设置
|
||||
```
|
||||
./app -style material
|
||||
```
|
||||
### 在Qt的环境变量中设置
|
||||
```
|
||||
QT_QUICK_CONTROLS_STYLE=universal ./app
|
||||
```
|
||||
### 使用配置文件
|
||||
```
|
||||
[Controls]
|
||||
Style=Material
|
||||
```
|
||||
官方的gallery案例用的是这种。
|
||||
网上有个哥们用的是:
|
||||
```
|
||||
if (sty == "mat") {
|
||||
qputenv("QT_QUICK_CONTROLS_CONF", ":/qtquickcontrols2material.conf");
|
||||
} else {
|
||||
qputenv("QT_QUICK_CONTROLS_CONF", ":/qtquickcontrols2universal.conf");
|
||||
}
|
||||
```
|
||||
本人用的是gallery案例中的方式,感觉通过设置环境变量来指定对应的conf不太灵活,所以上述方式仅供参考。<br>
|
||||
想要看懂conf文件需要看以下两篇文档
|
||||
## Qt Quick Controls 2 Configuration File
|
||||
文档:http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
|
||||
在默认情况下将文件放置于:/qtquickcontrols2.conf(也就是根目录)就会生效(需要设置QQuickStyle)
|
||||
### Controls Section
|
||||
Style:定义全局控件样式
|
||||
### XXXX Section
|
||||
对对应的style进行设置
|
||||
### Font Configuration
|
||||
设置字体,有以下几个属性:
|
||||
1. Family
|
||||
2. PointSize
|
||||
3. PixelSize
|
||||
4. StyleHint
|
||||
5. Weight
|
||||
6. Style
|
||||
### Palette Configuration
|
||||
Palette我不太清楚是干什么的
|
||||
## Material Style
|
||||
文档:http://doc.qt.io/qt-5/qtquickcontrols2-material.html#material-theme-attached-prop<br>
|
||||
你可以单独给某一些控件设置style,以下是对应的属性:
|
||||
### accent
|
||||
```
|
||||
Button {
|
||||
text: qsTr("Button")
|
||||
highlighted: true
|
||||
Material.accent: Material.Orange
|
||||
}
|
||||
```
|
||||
### background
|
||||
```
|
||||
Button {
|
||||
text: qsTr("Button")
|
||||
highlighted: true
|
||||
Material.background: Material.Teal
|
||||
}
|
||||
```
|
||||
### elevation
|
||||
控制阴影的属性
|
||||
```
|
||||
Pane {
|
||||
width: 120
|
||||
height: 120
|
||||
|
||||
Material.elevation: 6
|
||||
|
||||
Label {
|
||||
text: qsTr("I'm a card!")
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
```
|
||||
### foreground
|
||||
```
|
||||
Button {
|
||||
text: qsTr("Button")
|
||||
Material.foreground: Material.Pink
|
||||
}
|
||||
```
|
||||
### primary
|
||||
### theme
|
||||
三个可选项:
|
||||
1. Material.Light
|
||||
2. Material.Dark
|
||||
3. Material.System
|
||||
```
|
||||
Pane {
|
||||
Material.theme: Material.Dark
|
||||
|
||||
Button {
|
||||
text: qsTr("Button")
|
||||
}
|
||||
}
|
||||
```
|
||||
## 自定义主题
|
||||
文档:http://doc.qt.io/qt-5/qtquickcontrols2-customize.html#creating-a-custom-style
|
||||
推荐:http://www.cnblogs.com/Fuss/archive/2015/03/20/4353698.html<br>
|
||||
代码没怎么看,Control用的是1.0,可以作为参考,Github上有关这种UI定制的代码还是比较多,建议先去知乎搜索 “请问有哪些优质又开源的qml应用”
|
291
07-Other/Qt/QtQuick/Qt:解决QtQuick(QML)程序,在虚拟机或者某些环境下,动画速度过快的问题.md
Normal file
291
07-Other/Qt/QtQuick/Qt:解决QtQuick(QML)程序,在虚拟机或者某些环境下,动画速度过快的问题.md
Normal file
@@ -0,0 +1,291 @@
|
||||
## 参考网址
|
||||
https://blog.csdn.net/wsj18808050/article/details/54234956
|
||||
|
||||
Qt:获取屏幕物理长度和宽度(CM)
|
||||
https://blog.csdn.net/wsj18808050/article/details/54345537
|
||||
|
||||
Qt:5.8新特新,QtLite使用方法,以及缩减应用体积的效果
|
||||
https://blog.csdn.net/wsj18808050/article/details/55808104
|
||||
|
||||
QML 中的屏幕适配问题
|
||||
https://blog.csdn.net/qyvlik/article/details/51241425
|
||||
|
||||
QT5(9)HTTP POST GET COOKIE 网络编程
|
||||
```c++
|
||||
#include <QNetworkCookie> //单个cookie
|
||||
#include <QNetworkCookieJar> //储存cookie
|
||||
```
|
||||
https://blog.csdn.net/qq_16234613/article/details/53783391
|
||||
|
||||
qt 获取部分的cookie信息 如何把获取的cookie转换为QString类型 正则表达式
|
||||
https://blog.csdn.net/qq_22403265/article/details/51333226
|
||||
|
||||
### cookiebrowser使用webview载入cookie
|
||||
```
|
||||
m_store = m_webview->page()->profile()->cookieStore();
|
||||
m_store->loadAllCookies();
|
||||
```
|
||||
|
||||
### QML Settings 小的示例
|
||||
Setting 可以存储一些变量就想配置文件一样
|
||||
https://www.cnblogs.com/hbrw/p/6744094.html
|
||||
|
||||
### 直接导入qml
|
||||
Importing QML Document Directories
|
||||
目录结构:
|
||||
```
|
||||
myapp
|
||||
|- mycomponents
|
||||
|- CheckBox.qml
|
||||
|- DialogBox.qml
|
||||
|- Slider.qml
|
||||
|- main
|
||||
|- application.qml
|
||||
```
|
||||
那么可以:
|
||||
```
|
||||
import "../mycomponents"
|
||||
|
||||
DialogBox {
|
||||
CheckBox {
|
||||
// ...
|
||||
}
|
||||
Slider {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
但是创建一个命名空间来导入会更好
|
||||
```
|
||||
import "../mycomponents" as MyComponents
|
||||
|
||||
MyComponents.DialogBox {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### qml文件间通讯
|
||||
3.题回正传,直接上代码(以StackView管理页面为例)
|
||||
(1)page1.qml跳转到page2.qml传值
|
||||
```
|
||||
page1.qml
|
||||
|
||||
Rectangle
|
||||
{
|
||||
id:rect1
|
||||
...
|
||||
MouseArea {
|
||||
id: maStartQuery
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
if(!stackView.busy)
|
||||
stackView.push(Qt.resolvedUrl("qrc:///qml/page2.qml"),
|
||||
{name:"张三"})//给page2.qml的name传值“张三”,name必须在page2.qml中定义成属性
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
page2.qml定义如下
|
||||
|
||||
Rectangle
|
||||
{
|
||||
id:rect2
|
||||
...
|
||||
property string name:""//要传的值
|
||||
...
|
||||
|
||||
}
|
||||
```
|
||||
(2)page2.qml点击"确定"按钮时将结果返回给page1.qml
|
||||
|
||||
A.在page1.qml中增加一个函数clickedfunc,当点击page2.qml中"确定"按钮时调用;
|
||||
B.在page2.qml中增加一个属性containerqml,用来记录page1.qml;
|
||||
C.在从page1.qml跳转到page2.qml时,将rect1传给page2.qml的containerqml属性。
|
||||
```
|
||||
page1.qml
|
||||
Rectangle
|
||||
{
|
||||
id:rect1
|
||||
...
|
||||
MouseArea {
|
||||
id: maStartQuery
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
if(!stackView.busy)
|
||||
stackView.push(Qt.resolvedUrl("qrc:///qml/page2.qml"),
|
||||
{name:"张三",containerqml:rect1})
|
||||
}
|
||||
}
|
||||
|
||||
//当点击page2.qml中"确定"按钮时调用
|
||||
function clickedfunc(temp)
|
||||
{
|
||||
console.log("改成了:"+temp);
|
||||
stackView.pop();//返回到本页
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
page2.qml
|
||||
Rectangle
|
||||
{
|
||||
id:rect2
|
||||
...
|
||||
property variant containerqml: null
|
||||
property string name:""//要传的值
|
||||
...
|
||||
MouseArea {
|
||||
id: btnOK
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
containerqml.clickedfunc("李四");//调用page1.qml中的函数,实现了传返回值。
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
另一种就是信号与槽
|
||||
|
||||
### QtQuick 母版页
|
||||
```
|
||||
//~ Panel.qml
|
||||
Item {
|
||||
|
||||
property alias headerHeight: headerLoader.height
|
||||
property alias footerHeight: footerLoader.height
|
||||
|
||||
property Component headerComponent: null
|
||||
readonly property Item headerItem: headerLoader.item
|
||||
|
||||
Loader {
|
||||
id: headerLoader
|
||||
width: parent.width
|
||||
height: 40
|
||||
sourceComponent: headerComponent
|
||||
Binding {
|
||||
target: headerLoader.item
|
||||
property: "anchors.fill"
|
||||
value: headerLoader
|
||||
}
|
||||
}
|
||||
|
||||
property Component footerComponent: null
|
||||
readonly property Item footerItem: footerLoader.item
|
||||
|
||||
Loader {
|
||||
id: footerLoader
|
||||
width: parent.width
|
||||
height: 40
|
||||
anchors.bottom: parent.bottom
|
||||
Binding {
|
||||
target: footerLoader.item
|
||||
property: "anchors.fill"
|
||||
value: footerLoader
|
||||
}
|
||||
}
|
||||
|
||||
property Component contentComponent: null
|
||||
readonly property Item contentItem: contentLoader.item
|
||||
|
||||
Loader {
|
||||
id: contentLoader
|
||||
width: parent.width
|
||||
anchors.top: headerLoader.bottom
|
||||
anchors.bottom: footerLoader.top;
|
||||
Binding {
|
||||
target: contentLoader.item
|
||||
property: "anchors.fill"
|
||||
value: contentLoader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Panel {
|
||||
headerComponent: Rectangle {
|
||||
color: "black"
|
||||
}
|
||||
footerComponent: Rectangle {
|
||||
color: "black"
|
||||
}
|
||||
contentComponent: ListView {
|
||||
delegate: Rectangle { width: parent.width; height: 40; color: "green" }
|
||||
model: 10
|
||||
}
|
||||
}
|
||||
```
|
||||
### 全局单例模式
|
||||
|
||||
1. 入口文件的 id 和属性
|
||||
2. 静态 JavaScript 文件
|
||||
3. qml 单例,QML 实现
|
||||
4. qml 单例,c++ 实现
|
||||
5. 注册上下文属性
|
||||
|
||||
### 表单提交(不包括cookies)
|
||||
```
|
||||
function urlQuery(jsonObject) {
|
||||
var query = "";
|
||||
var i = 0;
|
||||
for(var iter in jsonObject) {
|
||||
|
||||
if(i > 0) {
|
||||
query += "&";
|
||||
}
|
||||
query += iter +"=" + encodeURI(jsonObject[iter]);
|
||||
i++;
|
||||
}
|
||||
// console.log("url query:", query);
|
||||
return query;
|
||||
}
|
||||
```
|
||||
```
|
||||
function setHeader(xhr, headers) {
|
||||
//"Content-Type":"application/x-www-form-urlencoded"
|
||||
for(var iter in headers) {
|
||||
xhr.setRequestHeader(iter, headers[iter]);
|
||||
}
|
||||
}
|
||||
|
||||
function ajax(method, url, headers, data, callable) {
|
||||
headers = headers || {};
|
||||
callable = callable || function(xhr) {
|
||||
console.log(xhr.responseText);
|
||||
}
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState == xhr.DONE) {
|
||||
callable(xhr);
|
||||
}
|
||||
}
|
||||
xhr.open(method, url);
|
||||
setHeader(xhr, headers);
|
||||
if("GET" === method) {
|
||||
xhr.send();
|
||||
} else {
|
||||
xhr.send(data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果带有指定名称的头部已经被指定了,这个头部的新值就是:之前指定的值,加上逗号、空白以及这个调用指定的值。
|
||||
如果 open() 调用指定了认证资格,XMLHttpRequest 自动发送一个适当的 Authorization 请求头部。但是,你可以使用 setRequestHeader() 来添加这个头部。类似地,如果 Web 服务器已经保存了和传递给 open() 的 URL 相关联的 cookie,适当的 Cookie 或 Cookie2 头部也自动地包含到请求中。可以通过调用 setRequestHeader() 来把这些 cookie 添加到头部。XMLHttpRequest 也可以为 User-Agent 头部提供一个默认值。如果它这么做,你为该头部指定的任何值都会添加到这个默认值后面。
|
||||
有些请求头部由 XMLHttpRequest 自动设置而不是由这个方法设置,以符合 HTTP 协议。这包括如下和代理相关的头部:
|
||||
Host
|
||||
Connection
|
||||
Keep-Alive
|
||||
Accept-charset
|
||||
Accept-Encoding
|
||||
If-Modified-Since
|
||||
If-None-Match
|
||||
If-Range
|
||||
Range
|
||||
|
||||
### XMLHttpRequest设置cookie的问题
|
||||
https://segmentfault.com/a/1190000004322487
|
||||
|
||||
### 如何获取指定objectName的QObject
|
23
07-Other/Qt/QtQuick/c++与QML混合编程笔记.md
Normal file
23
07-Other/Qt/QtQuick/c++与QML混合编程笔记.md
Normal file
@@ -0,0 +1,23 @@
|
||||
## 信号与槽
|
||||
信号与槽都可以在qml中访问
|
||||
### Q_INVOKABLE宏
|
||||
在定义一个类的成员函数时使用Q_INVOKABLE宏来修饰,就可以让该方法被元对象系统调用。(也就是注册到元对象系统中)
|
||||
例如:
|
||||
```
|
||||
Q_INVOKABLE void setAlgorithm(GenerateAlgorithm algorithm);
|
||||
```
|
||||
### Q_ENUMS宏
|
||||
使用Q_ENUMS(枚举名)的方式来注册枚举类型
|
||||
### Q_PROPERTY宏
|
||||
Q_PROPERTY宏用来定义可通过元对象系统访问的属性,通过它定义的属性,可以在QML中访问、修改,也可以通过在属性变化时发射特定信号。
|
||||
### 注册一个QML可用类型
|
||||
1. 实现c++类
|
||||
2. 注册QML类型
|
||||
3. 在QML中导入类型
|
||||
4. 在QML中创建由c++导出的类型的实例并使用
|
||||
|
||||
#### 注册QML类型
|
||||
1. qmlRegisterSingletonType() 用来注册单例类型
|
||||
2. qmlRegisterType() 注册非单例类型
|
||||
3. qmlRegisterTypeNotAvailable() 注册一个类型用来占位
|
||||
4. qmlRegisterUncreateableType() 注册具有附加属性的附加类型
|
24
07-Other/Qt/Qt多个子项目管理.md
Normal file
24
07-Other/Qt/Qt多个子项目管理.md
Normal file
@@ -0,0 +1,24 @@
|
||||
## subdirs
|
||||
新建项目-其他项目-子目录项目。
|
||||
|
||||
### 手动填在已有项目
|
||||
直接在
|
||||
```
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += \
|
||||
AssetEncrypt \
|
||||
OutlineTool \
|
||||
TechnicalSupport
|
||||
```
|
||||
|
||||
### 编译顺序
|
||||
不推荐使用顺序构建命令,因为这会损失多线程构建的性能优势。官方推荐使用编译依赖:
|
||||
```
|
||||
# 创建编译依赖以控制编译顺序
|
||||
TechnicalSupport.depends = AssetEncrypt
|
||||
TechnicalSupport.depends = OutlineTool
|
||||
```
|
||||
|
||||
## pri
|
||||
用于管理公共common pri,在Pro使用include(****.pri)引入。
|
103
07-Other/Qt/Qt总览.md
Normal file
103
07-Other/Qt/Qt总览.md
Normal file
@@ -0,0 +1,103 @@
|
||||
## Qt大佬blog
|
||||
专栏:《Qt 实战一二三》
|
||||
http://blog.csdn.net/column/details/qshare.html
|
||||
|
||||
qyvlik
|
||||
https://blog.csdn.net/qyvlik/
|
||||
## QT自定义精美换肤界面
|
||||
http://www.cnblogs.com/feiyangqingyun/p/3915657.html
|
||||
|
||||
Qt之自定义界面(窗体缩放-跨平台终极版)
|
||||
http://blog.csdn.net/liang19890820/article/details/50557240
|
||||
## QTableView Model
|
||||
QTabelView根据一行记录中的内容自动调整列宽度
|
||||
http://bbs.csdn.net/topics/390639311
|
||||
|
||||
Qt Model/View 学习笔记 (七)
|
||||
http://www.cppblog.com/yuanyajie/archive/2007/06/19/26641.html
|
||||
|
||||
QT:在QTableView中使用各种自定义委托
|
||||
http://www.linuxidc.com/Linux/2012-07/66820.htm
|
||||
|
||||
QT中Qtableview视图表格中点击表头进行排序
|
||||
http://www.cnblogs.com/googly/p/4584264.html
|
||||
|
||||
Qt之模型/视图(实时更新数据)
|
||||
http://blog.sina.com.cn/s/blog_a6fb6cc90101hhse.html
|
||||
## Qt读取excel文件
|
||||
### 可以用QSqlDatabase::addDatabase("QODBC"),这个挺不错
|
||||
```
|
||||
QStringList referList;
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
|
||||
db.setDatabaseName("DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=" + dir.filePath("test.xlsx"));
|
||||
if(db.open())
|
||||
{
|
||||
QSqlQuery query("select * from [Sheet1$A:A]",db); // Select range, place A1:B5 after $
|
||||
while (query.next())
|
||||
{
|
||||
QString dataStr= query.value(0).toString();
|
||||
if(dataStr != "0")
|
||||
{
|
||||
referList << dataStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
## 移植QT5.6到嵌入式开发板
|
||||
http://blog.csdn.net/lizuobin2/article/details/52673494
|
||||
|
||||
## 判断release与debug
|
||||
```
|
||||
#ifdef QT_NO_DEBUG
|
||||
qDebug() << "release mode";
|
||||
#else
|
||||
qDebug() << "debug mode";
|
||||
#endif
|
||||
```
|
||||
|
||||
## [Qt]新增UAC功能之requireAdministrator
|
||||
https://blog.csdn.net/luols/article/details/49996369
|
||||
https://blog.csdn.net/aqtata/article/details/17222691
|
||||
|
||||
## 如何把一个Qt项目拆成多个Qt子项目(pro、pri使用)
|
||||
https://blog.csdn.net/lee353086/article/details/70808057
|
||||
|
||||
Qt Creator管理多个项目
|
||||
https://blog.csdn.net/csxiaoshui/article/details/44102873
|
||||
|
||||
## 在Qt程序退出前时执行函数
|
||||
https://stackoverflow.com/questions/8165487/how-to-do-cleaning-up-on-exit-in-qt
|
||||
|
||||
## Qt自定义委托在QTableView中绘制控件、图片、文字
|
||||
http://blog.csdn.net/zhi379/article/details/28412189
|
||||
|
||||
## 加密你的SQLite
|
||||
http://foggry.com/blog/2014/05/19/jia-mi-ni-de-sqlite/
|
||||
|
||||
## QML分辨率适配
|
||||
QML 中的屏幕适配问题
|
||||
http://blog.csdn.net/qyvlik/article/details/51241425
|
||||
|
||||
QML怎么适配不同的设备
|
||||
http://blog.csdn.net/zhx6044/article/details/44180819
|
||||
## QGraphicsView
|
||||
QGraphicsView 框架学习(一)、图形元素的编辑
|
||||
https://blog.csdn.net/wishfly/article/details/77817091?locationNum=3&fps=1
|
||||
|
||||
Qt基础——获取QGraphicsScene的缩略图即导出到图片
|
||||
https://blog.csdn.net/lcl_data/article/details/8731892
|
||||
|
||||
Qt绘图之QGraphicsScene QGraphicsView QGraphicsItem详解
|
||||
https://www.cnblogs.com/cy568searchx/p/3502242.html
|
||||
|
||||
Qt 之图形视图框架
|
||||
https://blog.csdn.net/liang19890820/article/details/51966791
|
||||
|
||||
QGraphicsView 框架学习(一)
|
||||
https://blog.csdn.net/firebolt2002/article/details/46583589
|
||||
|
||||
基于Qt QGraphicsView的多点触摸绘图
|
||||
https://www.cnblogs.com/visonme/p/5435330.html
|
||||
|
||||
QGraphicsScene 管理 QGraphicsItem(单击/选择/移动/缩放/删除)
|
||||
https://blog.csdn.net/liang19890820/article/details/53504323
|
70
07-Other/Qt/为Qt中的SQLite添加密码并加密.md
Normal file
70
07-Other/Qt/为Qt中的SQLite添加密码并加密.md
Normal file
@@ -0,0 +1,70 @@
|
||||
## 前言
|
||||
因为Sqlite的源代码中只提供了Sqlite3_key()的接口,没有实现。所以Qt中的Sqlite没有密码功能。于是我找了一下资料,,并且总结一下思路。现成的方法在最后。
|
||||
|
||||
## SQLite历代版本与下载
|
||||
所有ReleaseTag:https://www.sqlite.org/cgi/src/taglist
|
||||
SQLite不提供明确的下载地址,所以地址需要开发者去猜……,也就是通过最新的地址以及你所需要的版本号去推:
|
||||
|
||||
例如:
|
||||
- sqlite-amalgamation-3240000:https://www.sqlite.org/2018/sqlite-amalgamation-3240000.zip
|
||||
- sqlite-dll-win32-x86-3240000.zip:https://www.sqlite.org/2018/sqlite-dll-win32-x86-3240000.zip
|
||||
- sqlite-dll-win64-x64-3240000.zip:https://www.sqlite.org/2018/sqlite-dll-win64-x64-3240000.zip
|
||||
- sqlite-amalgamation-3270200.zip:https://www.sqlite.org/2019/sqlite-amalgamation-3270200.zip
|
||||
- sqlite-dll-win64-x64-3270200.zip:https://www.sqlite.org/2019/sqlite-dll-win64-x64-3270200.zip
|
||||
|
||||
注意:
|
||||
- 年份
|
||||
- 版本号的小数点位在百位上
|
||||
|
||||
## 解决思路与大致过程
|
||||
编写一个QSQLDriver Plugins,并且实现Sqlite3_key()。
|
||||
|
||||
### 大致步骤
|
||||
- 在QtCreator中文件-新建文件或者项目-Library-c++Library来创建QSQLDriver Plugins(库类型选择Qt Plugin)。
|
||||
- 下载Qt源代码,并将\qtbase\src\plugins\sqldrivers\sqlite下的qsql_sqlite_p.h与qsql_sqlite.cpp文件复制到新建的插件目录下。
|
||||
- 修改2个文件中类名与创建插件的类名一致。并且修改open()函数(具体的请看参考资料)。
|
||||
- 下载sqlite源代码,并且实现Sqlite3_key(),注意该函数被宏设置为不编译。可以通过在项目中设置来解决也可以在头文件中直接设置宏为1来解决。
|
||||
- Sqlite3_key()的实现方法可以参考wxsqlite3或CipherSqlite。
|
||||
|
||||
## 现成的解决方法
|
||||
国人编写的插件:QtCipherSqlitePlugin。经测试5.14.2 MSVC2017 x64可以使用。使用起来很方便,直接用Qt打开sqlitecipher文件夹中的工程,直接切成release模式编译即可。
|
||||
|
||||
作者推荐的方法是将编译出lib与dll都放入源代码中的,不过我个人还是喜欢使用在项目中直接加载Plugin的方式来实现。这样可以方便后续的项目迁移与后续维护。大致代码如下:
|
||||
```
|
||||
QPluginLoader driverload(qApp->applicationDirPath()+"/plugin/sqldrivers/sqlitecipher.dll");
|
||||
if(driverload.load())
|
||||
{
|
||||
QSqlDriverPlugin *plugin=qobject_cast<QSqlDriverPlugin*>(driverload.instance());
|
||||
if(plugin)
|
||||
{
|
||||
QSqlDriver *driver=plugin->create("SQLITECIPHER");
|
||||
QSqlDatabase db;
|
||||
db=QSqlDatabase::addDatabase(driver);
|
||||
db.setDatabaseName("mydatabase.db");
|
||||
db.setPassword("123456");
|
||||
if(db.open())
|
||||
{
|
||||
QSqlQuery qry(db);
|
||||
qry.exec("create table t_trade(order_id varchar(100))");
|
||||
qry.exec("insert into t_trade(order_id) values('10001')");
|
||||
qry.exec("insert into t_trade(order_id) values('10002')");
|
||||
qry.exec("select * from t_trade");
|
||||
while(qry.next())
|
||||
{
|
||||
qDebug()<<qry.value(0).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
PS.debug与release的dll是不通用的,所以需要编译两份dll,并且载入时进行判断!
|
||||
|
||||
- QtCipherSqlitePlugin地址:
|
||||
https://github.com/devbean/QtCipherSqlitePlugin
|
||||
- 编译方法:https://github.com/devbean/QtCipherSqlitePlugin/wiki/How-to-compile
|
||||
- 使用方法:https://github.com/devbean/QtCipherSqlitePlugin/wiki/How-to-use
|
||||
|
||||
## 参考资料
|
||||
- https://www.devbean.net/2012/07/qt-sqlite-plugin-with-encryption/
|
||||
- https://www.cnblogs.com/WushiShengFei/p/9707244.html
|
163
07-Other/Qt/在Qt中使用Mupdf库显示pdf文档.md
Normal file
163
07-Other/Qt/在Qt中使用Mupdf库显示pdf文档.md
Normal file
@@ -0,0 +1,163 @@
|
||||
## 前言
|
||||
最近有个pdf的需求,Qt竟然没有显示pdf的api,着实令人郁闷。之后我尝试用了poppler,但是光配置编译工程就相当麻烦了,没有cmake等开源项目编译经验的人完全一脸懵逼。PDFium也是同理(手头上没有vpn也无法尝试)。感觉Mupdf编译器起来比较简单,所以就来用了一下。
|
||||
|
||||
本人使用的版本是Mupdf1.12.0+Qt5.9.3+vs2015
|
||||
|
||||
## 下载Mupdf库
|
||||
https://mupdf.com/downloads/
|
||||
|
||||
## 编译Mupdf
|
||||
在mupdf-1.12.0-source\platform\win32目录下就有现成的mupdf.sln。
|
||||
这里需要注意:这个工程默认使用的是/MT,而Qt MSVC默认用的是/MD,所以需要修改编译工程设置。我们这里只需要在编译工程中修改就可以了。
|
||||
以下是一些有关QMake中设置运行库属性 /md /md /mt /mtd 的相关参考
|
||||
- http://blog.csdn.net/caoshangpa/article/details/51416077
|
||||
- http://www.cnblogs.com/codingmylife/archive/2010/05/08/1730832.html
|
||||
- http://www.voidcn.com/article/p-hhosrsia-hq.html
|
||||
|
||||
工程里默认生成的是都是静态库,请注意!根据测试需要的分别是libmupdf.lib、libresources.lib、libthirdparty.lib这三个库(只使用了docs\examples\example.c的代码,使用别的函数可能需要再编译别的工程)
|
||||
|
||||
分别修改解决方案中的libmupdf、libthirdparty、libresources这三个工程,将debug下改成/MDd,release下改成/MD,编译即可得到这3个文件。其中libresources只有release版本的,所以debug模式下,我也引用这个文件。
|
||||
|
||||
## 在Qt工程中引入Mupdf静态库
|
||||
- 引入lib文件
|
||||
- 新建一个工程,在工程的图标上右键——添加库——外部库。平台只勾选windows,链接选择静态,之后选择对应的库就可以了。(本人将debug与release编译的分别放在debug与release文件夹中)
|
||||
- 添加包含目录
|
||||
- 将Mupdf目录中的include复制到工程目录下(本人又新建了一个mupdf,将所有文件都放在里面了)
|
||||
- 本人是这么写的,具体可以参考源代码:
|
||||
- `INCLUDEPATH += $$PWD/mupdf/include/`
|
||||
|
||||
之后运行QMake。
|
||||
|
||||
## 编写代码进行测试
|
||||
```c++
|
||||
#include "widget.h"
|
||||
#include "ui_widget.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QLabel>
|
||||
|
||||
#include "mupdf/fitz.h"
|
||||
#include "mupdf/pdf.h"
|
||||
|
||||
Widget::Widget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::Widget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
char *input = const_cast< char* >("document.pdf");
|
||||
float zoom, rotate;
|
||||
int page_number, page_count;
|
||||
fz_context *ctx;
|
||||
fz_document *doc;
|
||||
fz_pixmap *pix;
|
||||
fz_matrix ctm;
|
||||
int x, y;
|
||||
|
||||
//第一页为0
|
||||
page_number=1;
|
||||
//100%缩放比
|
||||
zoom=100;
|
||||
//旋转为0
|
||||
rotate=0;
|
||||
|
||||
//创建上下文
|
||||
ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
|
||||
if (!ctx)
|
||||
{
|
||||
qDebug()<<stderr<<"cannot create mupdf context";
|
||||
return;
|
||||
}
|
||||
|
||||
//注册文档控制
|
||||
fz_try(ctx)
|
||||
fz_register_document_handlers(ctx);
|
||||
fz_catch(ctx)
|
||||
{
|
||||
qDebug()<<stderr<<"cannot register document handlers:"<< fz_caught_message(ctx);
|
||||
fz_drop_context(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
//打开文档
|
||||
fz_try(ctx)
|
||||
doc = fz_open_document(ctx, input);
|
||||
fz_catch(ctx)
|
||||
{
|
||||
qDebug()<<stderr<< "cannot open document:"<< fz_caught_message(ctx);
|
||||
fz_drop_context(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
//取得总的页数
|
||||
fz_try(ctx)
|
||||
page_count = fz_count_pages(ctx, doc);
|
||||
fz_catch(ctx)
|
||||
{
|
||||
qDebug()<<stderr<< "cannot count number of pages:"<< fz_caught_message(ctx);
|
||||
fz_drop_document(ctx, doc);
|
||||
fz_drop_context(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (page_number < 0 || page_number >= page_count)
|
||||
{
|
||||
qDebug()<<stderr<< "page number out of range: "<< page_number + 1<<"page count:"<<page_count;
|
||||
fz_drop_document(ctx, doc);
|
||||
fz_drop_context(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
//计算缩放以及旋转
|
||||
fz_scale(&ctm, zoom / 100, zoom / 100);
|
||||
fz_pre_rotate(&ctm, rotate);
|
||||
|
||||
//渲染pixmap
|
||||
fz_try(ctx)
|
||||
pix = fz_new_pixmap_from_page_number(ctx, doc, page_number, &ctm, fz_device_rgb(ctx), 0);
|
||||
fz_catch(ctx)
|
||||
{
|
||||
qDebug()<<stderr<< "cannot render page: %s\n"<< fz_caught_message(ctx);
|
||||
fz_drop_document(ctx, doc);
|
||||
fz_drop_context(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
//渲染成图片
|
||||
// unsigned char *samples = fz_pixmap_samples(ctx, pix);
|
||||
unsigned char *samples = pix->samples;
|
||||
int width = fz_pixmap_width(ctx, pix);
|
||||
int height = fz_pixmap_height(ctx, pix);
|
||||
|
||||
QImage image(samples, width, height,QImage::Format_RGB888);
|
||||
|
||||
QLabel *label=new QLabel;
|
||||
label->setPixmap(QPixmap::fromImage(image));
|
||||
ui->layout->addWidget(label);
|
||||
|
||||
// if (!image.save("a.png")) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
//回收内存
|
||||
fz_drop_pixmap(ctx, pix);
|
||||
fz_drop_document(ctx, doc);
|
||||
fz_drop_context(ctx);
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
```
|
||||
|
||||
## 参考代码
|
||||
https://github.com/blueroseslol/QtMupdf
|
||||
|
||||
找到一个之前有人封装的库,不过经过测试是无法成功编译的,不过可以参考一下mupdf库的用法。
|
||||
https://github.com/xiangxw/mupdf-qt
|
||||
|
||||
别的参考:
|
||||
http://blog.csdn.net/chenyijun/article/details/42582977
|
Reference in New Issue
Block a user