一、Qt窗口坐标体系
以左上角为原点,X向右增加,Y向下增加;
对于嵌套窗口,其坐标 是相对于父窗口来说的。
二、基础窗口部件QWidget
QWidget类是所有用户界面对象的基类,被称为基础窗口部件。
所有窗口及窗口控件都是从QWidget直接或者间接派生出来的。
QWidget继承自QObject类和QPaintDevice类
QObject类是所有支持Qt对象模型(Qt Object Model)的对象的基类
QPaintDevice类是所有可以绘制的对象的基类
可以通过Qt助手(Qt Assistant)中的索引搜索
1.代码书写位置
向导方式创建项目
推荐写在mywidget.cpp中
#include "mywidget.h"MyWidget::MyWidget(QWidget *parent) : QWidget(parent){ //构造方法,代码推荐写在这里 //设置窗口标题 this->setWindowTitle("我的一个Widget"); //设置窗口大小(可变大小) //this->resize(800,600); //设置窗口大小(不可变大小) this->setFixedSize(400,300); //设置窗口的背景颜色 this->setAutoFillBackground(true); //QPalette类包含每个小部件状态的颜色组 QPalette pa = this->palette(); //将给定颜色角色的笔刷设置为调色板中所有组的指定笔刷 pa.setBrush(QPalette::Background, QBrush(Qt::green)); setPalette(pa); //设置窗口透明度,0-1 this->setWindowOpacity(0.5);}MyWidget::~MyWidget(){}
代码中包含.h头文件
#include "mywidget.h"
#ifndef MYWIDGET_H#define MYWIDGET_H#include class MyWidget : public QWidget{ Q_OBJECTpublic: MyWidget(QWidget *parent = 0); ~MyWidget();};//1、如果parent=0 ( 默认值),则新建的窗口部件一定将是一个窗口;//2、如果parent != 0,则新建的窗口部件可能是子窗口部件也有可能是一个窗口,由它参数Qt::WindowFlags属性决定;#endif // MYWIDGET_H
在.h头文件中,包含头文件#include
,因为下面所有要用到的类,如QApplication,QWidget等,都包含在QtWidgets模块中,为了简便,只包含了QtWidgets的头文件。
窗口部件(Widget)简称部件,是Qt中建立用户界面的主要元素。像主窗口、对话框、标签、还有以后要介绍到的按钮、文本输人框等都是窗口部件。这些部件可以接收用户输入、显示数据和状态信息,并且在屏幕上绘制自己。有些也可以作为一个容器来放置其他部件。Qt中把没有嵌入到其他部件中的部件称为窗口,一般窗口都有边框和标题栏,就像程序中的widget一样。QMainWindow和大量的QDialog子类是最一般的窗口类型。
窗口就是没有父部件的部件,所以又称为顶级部件( top-level wid-get);与其相对的是非窗口部件,又称为子部件(child widget)。在Qt中大部分部件被用作子部件,嵌入在别的窗口中。这部分内容可以查看关键字QtWidgets和 Window and Dialog Widgets。
QWidget提供了自我绘制和处理用户输入等基本功能,Qt提供的所有界面元素不是QWidget的子类就是与QWidget的子类相关联。要设计自己的窗口部件,可以继承自QWidget或者是它的子类。
2.按钮的创建
父窗口和子窗口
如果把一个窗口作为某个容器窗口的子窗口,那么该窗口将被束缚在其父窗口的内部,并伴随父窗口一起移动、隐藏、显示和关闭,否则该窗口将作为独立窗口显示在屏幕上,且游离于其它窗口之外。
只有QWidget及其子类的对象可以做为其它窗口的容器
父窗口的析构函数负责销毁其所有的子窗口对象,因此即使子窗口对象是通过new运算符动态创建的,也无需因为没有显式地delete它们而担心内存泄漏的风险(在Qt中销毁父对象的时候会自动销毁子对象)。
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
设置窗口的位置和大小
void move (int x, int y);
void resize (int w, int h);
常用的父窗口类有如下三个:
QWidget
QMainWindow(主窗口,通常由标题栏、菜单栏、工具条、状态栏以及中央客户区组成) //QWidget的直接子类
QDialog(对话框类,管理多个不同种类的交互式部件)//QWidget的直接子类
案例操作:
在构造函数中添加(运行后发现Button一闪而过,没有出现在窗口上)
#include "mywidget.h"#include MyWidget::MyWidget(QWidget *parent) : QWidget(parent){ //构造方法,代码推荐写在这里 //设置窗口标题 this->setWindowTitle("我的一个Widget"); //设置窗口大小(可变大小) //this->resize(800,600); //设置窗口大小(不可变大小) this->setFixedSize(400,300); //设置窗口的背景颜色 this->setAutoFillBackground(true); //QPalette类包含每个小部件状态的颜色组 QPalette pa = this->palette(); //将给定颜色角色的笔刷设置为调色板中所有组的指定笔刷 pa.setBrush(QPalette::Background, QBrush(Qt::green)); setPalette(pa); //设置窗口透明度,0-1 this->setWindowOpacity(0.9); QPushButton button; button.show();}MyWidget::~MyWidget(){}
改进:在.h头文件中加入QPushButton指针(未指定父对象,按钮窗口会单独显示)
#ifndef MYWIDGET_H#define MYWIDGET_H#include #include class MyWidget : public QWidget{ Q_OBJECTpublic: MyWidget(QWidget *parent = 0); ~MyWidget(); //按钮指针 QPushButton *button;};//1、如果parent=0 ( 默认值),则新建的窗口部件一定将是一个窗口;//2、如果parent != 0,则新建的窗口部件可能是子窗口部件也有可能是一个窗口,由它参数Qt::WindowFlags属性决定;#endif // MYWIDGET_H
#include "mywidget.h"#include MyWidget::MyWidget(QWidget *parent) : QWidget(parent){ //构造方法,代码推荐写在这里 //设置窗口标题 this->setWindowTitle("我的一个Widget"); //设置窗口大小(可变大小) //this->resize(800,600); //设置窗口大小(不可变大小) this->setFixedSize(400,300); //设置窗口的背景颜色 this->setAutoFillBackground(true); //QPalette类包含每个小部件状态的颜色组 QPalette pa = this->palette(); //将给定颜色角色的笔刷设置为调色板中所有组的指定笔刷 pa.setBrush(QPalette::Background, QBrush(Qt::green)); setPalette(pa); //设置窗口透明度,0-1 this->setWindowOpacity(0.9);// QPushButton button;// button.show(); button = new QPushButton; button->show();}MyWidget::~MyWidget(){}
指定按钮的父类是窗口
#include "mywidget.h"#include MyWidget::MyWidget(QWidget *parent) : QWidget(parent){ //构造方法,代码推荐写在这里 //设置窗口标题 this->setWindowTitle("我的一个Widget"); //设置窗口大小(可变大小) this->resize(800,600); //设置窗口大小(不可变大小) //this->setFixedSize(400,300); //设置窗口的背景颜色 this->setAutoFillBackground(true); //QPalette类包含每个小部件状态的颜色组 QPalette pa = this->palette(); //将给定颜色角色的笔刷设置为调色板中所有组的指定笔刷 pa.setBrush(QPalette::Background, QBrush(Qt::green)); setPalette(pa); //设置窗口透明度,0-1 this->setWindowOpacity(0.9);// QPushButton button;// button.show(); button = new QPushButton; button->show(); button->setParent(this);}MyWidget::~MyWidget(){}
可以设置button的一些属性resize、move等,此处略
3.编码
#include "mainwindow.h"#include #include #include #include int main(int argc, char *argv[]){ QApplication a(argc, argv); // 创建编码对象 QTextCodec* codec = QTextCodec::codecForName("gbk"); // 将要显示的gbk编码的字符串转换成unicode QLabel label(codec->toUnicode("我是标签")); label.show(); QPushButton btn(codec->toUnicode("我是按钮")); btn.show(); return a.exec();}
如果想把两个窗口整合到父窗口上
#include "mainwindow.h"#include #include #include #include int main(int argc, char *argv[]){ QApplication a(argc, argv); QMainWindow w; w.resize(400,400); // 创建编码对象 QTextCodec* codec = QTextCodec::codecForName("gbk"); // 将要显示的gbk编码的字符串转换成unicode QLabel label(codec->toUnicode("我是标签"),&w); label.move(100,100); QPushButton btn(codec->toUnicode("我是按钮"),&w); btn.move(200,200); w.show(); return a.exec();}
三、信号和槽机制
1. 什么是信号和槽
信号和槽是QT自行定义的一种通信机制,用于两个对象之间的通信,实现对象之间的数据交互。
当用户或系统触发了一个动作,导致某个控件的状态发生了改变,该控件就会发射一个信号(signal),即调用其类中一个特定的成员函数(信号),同时还可能携带有必要的参数。
槽(slot)和普通的成员函数几乎没有太多区别,可以是公有的、保护的或私有的,可以被重载,也可以被覆盖,其参数可以是任意类型,并可以像普通成员函数一样调用。
槽函数与普通成员函数的差别并不在于其语法特性,而在于其功能。槽函数更多体现为对某种特定信号的处理,可以将槽和其它对象信号建立连接(connect),这样当发射信号时,槽函数将被触发和执行,进而来完成具体功能。
2.信号的定义
class XX:public QObject{ Q_OBJECTsignals: void signal_func(..); //信号函数};
注:信号函数只需声明,不能写定义
3.槽的定义
class XX:public QObject{ Q_OBJECTpublic slots: void slot_func(...){...}//槽函数};
注:槽函数可以连接到某个信号上,当信号被发射时,槽函数将被触发和执行,另外槽函数也可以当做普通的成员函数直接调用
信号和槽连接起来,是通过QObject类的connect(成员函数完成的
Qobject :: connect( const Qobject * sender, const char * signal, const Qobject * receiver, const char * mothod);
sender:信号发送对象指针
signal:要发送的信号函数,可以使用“SIGNAL(..)” 宏进行类型转换
receiver:信号的接收对象指针
method:接收信号后要执行的槽函数,可以使用“SLOT(..)” 宏进行类型转换
4.案例1
创建Qt应用程序,包含标签和按钮两个控件,实现点击按钮关闭标签
按钮点击时发送信号:clicked()
实现标签关闭功能的槽:close()
#include "widget.h"#include #include #include int main(int argc, char *argv[]){ QApplication a(argc, argv); QWidget parent; parent.resize(400,400); QLabel label("信号和槽",&parent); label.move(150,150); QPushButton button("关闭",&parent); button.move(300,300); button.resize(100,100); parent.show(); QObject::connect(&button,SIGNAL(clicked()),&a,SLOT(closeAllWindows())); return a.exec();}
进阶版
#include "dialog.h"#include #include #include #include int main(int argc, char *argv[]){ QApplication app(argc, argv); Dialog parent; parent.move(100,100); parent.resize(300,200); QLabel label("标签",&parent); label.move(50,30); label.resize(100,35); QLabel label2("标签",&parent); label2.move(180,30); label2.resize(100,35); QPushButton btn("关闭label",&parent); btn.move(50,100); btn.resize(100,35); QPushButton btn2("关闭所有",&parent); btn2.move(180,100); btn2.resize(100,35); parent.show(); QObject::connect(&btn,SIGNAL(clicked(void)), &label,SLOT(close(void))); QObject::connect(&btn,SIGNAL(clicked(void)), &label2,SLOT(close(void))); QObject::connect(&btn2,SIGNAL(clicked(void)), &app,SLOT(closeAllWindows(void))); return app.exec();}
5.信号和槽连接的语法要求
信号和槽参数要一致
QObject::connect(A,SIGNAL(sigfun(int)), B,SLOT(slotfun(int)));//okQObject::connect(A,SIGNAL(sigfun(int)), B,SLOT(slotfun(int,int)));//error
可以带有缺省参数
QObject::connect(A,SIGNAL(sigfun(int)), B,SLOT(slotfun(int,int=0)));//ok
信号函数的参数可以多于槽函数,多余参数将被忽略
QObject::connect(A,SIGNAL(sigfun(int,int)), B,SLOT(slotfun(int)));//ok
6.信号和槽连接的应用
一个信号可以被连接到多个槽(一对多)
QObject::connect(A,SIGNAL(sigfun(int)), B1,SLOT(slotfun1(int)));//okQObject::connect(A,SIGNAL(sigfun(int)), B2,SLOT(slotfun2(int)));//ok
多个信号也可以连接到同一个槽(多对一)
QObject::connect(A1,SIGNAL(sigfun1(int)), B,SLOT(slotfun(int)));//okQObject::connect(A2,SIGNAL(sigfun2(int)), B,SLOT(slotfun(int)));//ok
两个信号可以直接连接(信号级联)//了解
QObject::connect(A1,SIGNAL(sigfun1(int)), A2,SIGNAL(sigfun2(int)));//ok
7.案例2
创建Qt应用程序,包含滑块(QSlider)和选值框(QSpinBox),通过信号和槽的机制,保持同步运行
QSlider//滑块
void setRange (int min, int max); // 设置滑动范围void setValue (int)[slot]; // 设置当前位置void valueChanged (int value) [signal]; // 滑块滑动时发送信号
QSpinBox//选值框
void setRange (int min, int max); // 设置数值改变范围void setValue (int)[slot]; // 设置当前数值void valueChanged (int value) [signal]; // 选值框数值改变时发送信号
代码:
#include "dialog.h"#include //滑块#include //选值框#include int main(int argc, char *argv[]){ QApplication app(argc, argv); Dialog parent; parent.resize(300,300); //水平 QSlider slider(Qt::Horizontal,&parent); slider.resize(150,30); slider.move(50,50); //设置取值的范围 slider.setRange(0,100); //滑块的当前值,在取值范围之内 slider.setValue(50); QSpinBox spinBox(&parent); spinBox.move(50,100); spinBox.resize(150,30); spinBox.setRange(0,100); spinBox.setValue(50); parent.show(); //拖动滑块更改选值 QObject::connect(&slider,SIGNAL(valueChanged(int)),&spinBox,SLOT(setValue(int))); //更改选值更改滑块位置 QObject::connect(&spinBox,SIGNAL(valueChanged(int)),&slider,SLOT(setValue(int))); return app.exec();}