第一个应用程序
#include "widget.h"
#include <QApplication>
#include<QLabel>
int main(int argc, char *argv[])
{//创建qt应用程序对象QApplication a(argc, argv);//创建标签控件QLabel label("你好");//来吧,展示label.show();Widget w;w.show();//让应用程序进入事件return a.exec();
}
Qt中文编码问题
Qt内部编码:
- Qt应用程序编程接口及其内部实现所使用的字符,都是以unicode编码(UTF-16),也就是Unicode就是Qt的内部编码
外部编码:
- 程序源代码中使用的字面值形式的字符和字符串、用户通过程序界面输入的字符和字符串,以及程序通过文件、网络、进程间通信或其它媒介读取的字符和字符串,受系统环境等因素的影响,通常会是各种各样的编码格式,一般将其统称为外部编码
QString::QString(const char *str)
/*Constructs a string initialized with the 8-bit string str. The given const char pointer is converted to Unicode using the fromUtf8() function.*/
编码转换
- 默认情况下,Qt5可以正确理解uft-8格式编码,并将其自动转换为内部的unicode编码,如果使用utf-8的中文字符串总是能够正确显示,但是如果使用其它格式的外部编码,比如windows中常用的GBK编码,将会出现乱码现象
- 通过QTextCodec实现编码转换 QTextCodec *codec =QTextCodec::codecForName(“GBK”);
- QString string = codec->toUnicode (“GBK编码的中文字符串”);
所以我们需要尽量使用UTF8
父窗口
-创建控件时,可以指定停靠在某个父窗口上面,这时控件将作为子窗口被束缚在其父窗口的内部,并伴随父窗口一起移动、隐藏、显示和关闭;否则该控件将作为独立窗口显示在屏幕上,且游离于其它窗口之外
QWidget及其子类的对象可以做为其它控件的父窗口常用的父窗口类又如下三个∶
- QWidget
- QMainWindow(主窗口)//QWidget的直接子类
- QDialog(对话框)//QWidget的直接子类
父窗口的析构函数回自动销毁其所有的子窗口对象,因此即使子窗口对象是通过new操作符动态创建的,可以不显式的执行delete操作,而且不用担心内存泄漏的问题,只要保证父窗口对象被正确销毁,其子窗口也将随之被销毁
#include "widget.h"
#include <QApplication>
#include<QLabel>
#include<QDialog>
#include<QMainWindow>
#include<QPushButton>int main(int argc, char *argv[])
{QApplication app(argc,argv);
// QWidget parent;QDialog parent;
// QMainWindow parent;parent.move(50,50);parent.resize(320,320);QLabel label("我是标签",&parent);label.move(20,40);QPushButton button("我是按钮",&parent); //栈对象button.move(20,100);button.resize(80,80);QPushButton* button2 = new QPushButton("我是按钮",&parent); //堆对象parent.show();//让应用程序进入事件return app.exec();
}
信号和槽
- 信号和槽是QT自行定义的一种通信机制,实现对象之间的数据交互。当用户或系统触发了一个动作,导致某个控件的状态发生了改变,该控件就会发射一个信号,即调用其类中一个特定的成员函数(信号),同时还可能携带有必要的参数
- 槽和普通的成员函数几乎没有太多区别,可以是公有的、保护的或私有的,可以被重载,也可以被覆盖,其参数可以是任意类型,并可以像普通成员函数一样调用
- 槽函数与普通成员函数的差别并不在于其语法特性,而在于其功能。槽函数更多体现为对某种特定信号的处理,可以将槽和其它对象信号建立连接,这样当发射信号时,槽函数将被触发和执行,进而来完成具体功能
信号的定义:
信号的定义
class XX:public QObject
{
Q_OBJECT
signals:void signal_func(..);//信号函数
};
信号函数只需声明,不能写定义
槽的定义:
class xx:public QObject{
Q_OBJECT
public slots:
void slot_func(...){...}//槽函数
};
注︰槽函数可以连接到某个信号上,当信号被发射时,槽函数将被触发和执行,另外槽函数也可以当做普通的成员函数直接调用
信号和槽的连接:
QObject::connect( const QObject * sender, const char * signal
const Qobject * receiver, const char * method) ;
参数:
sender:信号发送对象指针
signal:要发送的信号函数,可以使用“SIGNAL(..)”宏进行类型转换
receiver:信号的接收对象指针
method:接收信号后要执行的槽函数,,可以使用“SLOT(..)宏进行类型转换
//点击按钮关闭窗口QObject::connect(&button,SIGNAL(clicked(void)),&label,SLOT(close()));//增加退出按钮,实现退出QObject::connect(&button3,SIGNAL(clicked(bool)),&parent,SLOT(close()));
信号和槽连接的语法要求:
信号和槽连接的语法要求信号和槽参数要一致
Q0bject:connect(A,SIGNAL(sigfun(int)), B,SLOT(slotfun(int)));//ok
Q0bject:connect(A,SIGNAL(sigfun(int)), B,SLOT(slotfun(int,int));//error
- 可以带有缺省参数
Q0bject:connect(A,SIGNAL(sigfun(int)), B,SLOT(slotfun(int,int=O)));//ok
- 信号函数的参数可以多于槽函数,多余参数将被忽略
QObject::connect(A,SIGNAL(sigfun(int,int)),B,SLOT(slotfun(int));//ok
- 一个信号可以连接多个槽(但是执行顺序不确定)
- 多个信号可以连接一个槽
- 两个信号可以直接连接(信号级联),应用比较少。
一个小例子
int main(int argc, char *argv[])
{QApplication app(argc,argv);QDialog parent;parent.resize(320,240);//创建水平滑块QSlider slider(Qt::Horizontal,&parent);slider.move(20,100);slider.setRange(0,200);//创建选址框QSpinBox spin(&parent);spin.move(220,100);spin.setRange(0,200);//滑块滑动影响选址框QObject::connect(&slider,SIGNAL(valueChanged(int)),&spin,SLOT(setValue(int)));QObject::connect(&spin,SIGNAL(valueChanged(int)),&slider,SLOT(setValue(int)));parent.show();//让应用程序进入事件return app.exec();
}
关于面向对象的Qt编程
没啥好说的,实现一个加法计算器吧
加法计算器
- 通过面向对象的编程思想实现加法计算器
- 输入两个数字,按“=”按钮显示计算结果
- 两个操作数必须都是合法的数字,拒绝接受任何非法字符
- 两个操作数必须全部合法,“=”按钮才被激活,否则禁用(不可以点击)
- 显示结果的控件只可查看不可修改,但支持复制到剪贴板
- 所有子窗口的大小和位置随主窗口的缩放自动调整至最佳
写了半个多小时,IDE卡死了,你码没了!!!!!!!!!!!!艹
Time::Time(QWidget *parent): QWidget(parent)
{ui.setupUi(this);//初始化界面m_label = new QLabel(this);m_label->setFrameStyle(QFrame::Panel | QFrame::Sunken);m_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);//设置字体大小QFont font;font.setPointSize(20);m_label->setFont(font);//获取系统时间按钮m_button = new QPushButton("get time", this);m_button->setFont(font);//垂直布局器QVBoxLayout* layout = new QVBoxLayout(this);layout->addWidget(m_label);layout->addWidget(m_button);setLayout(layout);//信号和槽connect(m_button, SIGNAL(clicked()),this, SLOT(getTime()));
}void Time::getTime()
{qDebug() << "gettime";//获取当前时间QTime time = QTime::currentTime();//将时间转换为字符串形式QString str = time.toString("hh:mm:ss");//显示时间m_label->setText(str);}
class Time : public QWidget
{Q_OBJECT public:Time(QWidget *parent = Q_NULLPTR);private:Ui::TimeClass ui;
private:QLabel* m_label;QPushButton* m_button;
public slots://获取系统时间槽函数void getTime(void);
};
有缺陷,但我不想改了。
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);connect(ui->m_btnBox,SIGNAL(accepted()),this,SLOT(onAccepted()));connect(ui->m_btnBox,SIGNAL(accepted()),this,SLOT(onRejected()));
}Widget::~Widget()
{delete ui;
}
//处理OK
void Widget::onAccepted(void)
{if(ui->m_usernameEdit->text() == "123" &&ui->m_passwdEdit->text() == "123"){qDebug()<<"登陆成功";close();//关闭窗口}else{QMessageBox msgBox(QMessageBox::Critical,"Error","用户名或密码错误",QMessageBox::Ok,this);msgBox.exec();}}//处理取消
void Widget::onRejected(void)
{QMessageBox msgBox(QMessageBox::Question,"登录","是否确定要取消登录",QMessageBox::Yes | QMessageBox::No,this);if(msgBox.exec() == QMessageBox::Yes){close();}}
Qt的事件处理机制
什么是事件?
- 在Qt中,是以事件驱动UI工具集,包括信号和槽都依赖于Qt的事件处理机制
- 通常事件是由窗口系统或者Qt自身产生的,用以响应所发生的各类事情,比如用户按下并释放了键盘或者鼠标、窗口因缩放而需要重绘、定时器到期而应有所动作
如何处理事件?
-
在Qt中,事件被封装成对象,所有的事件对象类型都继承自抽象类QEvent
-
当事件发生时,首先被调用的是Q0bject类中的虚函数event(),其参数(QEvent)标识了具体的
心事件类型 -
在Qt桌面应用(Qt Widgets Application)开发中,QWidget类覆盖了其基类中的event()虚函数,并根据具体事件调用具体事件处理函数︰
-
所有的事件处理函数都是虚函数,可以被QWidget的子类覆盖,以提供针对不同窗口控件类型的事件处理,控件的使用者所关心的往往是定义什么样的槽处理什么样的信号,而控件的实现者则更关心覆盖哪些事件处理函数
-
如果程序员希望在窗口中自定义的处理事件,可以继承QWidget或者其子类,比如QDialog.QMainWindow,在自定义的窗口子类中重写事件处理函数,当相应事件被触发时,会利用多态的语法机制,所执行到的事件处理函数将是子类中重写的版本,从而实现程序员先要的事件处理效果
案例:
//槽函数
void ShowimageDialog::on_m_btnPrev_clicked()
{if(--m_index<0){m_index = 8;}update();
}void ShowimageDialog::on_m_btnNext_clicked()
{if(++m_index>8){m_index = 1;}update();
}
//斜体字是虚函数
void ShowimageDialog::paintEvent(QPaintEvent*)
{//qDebug("paintEvent");// 1)创建爱你画家对象QPainter painter(this);// 2)获取绘图所在的矩形区域QRect rect = ui->frame->frameRect();//坐标值得平移,奇妙的语法rect.translate(ui->frame->pos());// 3)构建要绘制的图形对象QImage image(":/images/1 ("+QString::number(m_index)+").jpg");// 4) 使用painter将image图片画到rectpainter.drawImage(rect,image);
}
定时器
定时器事件
Qt通过两套机制为应用程序提供定时功能
- 定时器事件,由Q0bject提供
- 定时器信号,由QTimer提供>通过定时器事件实现定时器
- int Q0bject.startTimer (int interval;启动定时器,以后每隔interval毫秒触发一次定时器事件,返回定时器ID
- void Qobject:timerEvent (QTimerEvent* ) [virtual];//定时器事件处理函数.
- -void Qobject::killTimer(int id);//关闭参数id所标识的定时器
#include "erinedialog.h"
#include "ui_erinedialog.h"ErineDialog::ErineDialog(QWidget *parent) :QDialog(parent),ui(new Ui::ErineDialog)
{ui->setupUi(this);m_index = 0;isStarted =false;qsrand(QTime::currentTime().msec());//加载所有图片到容器loadPhotos("./photos");qDebug()<<"加载图片个数"<<m_vecPhotos.size();}ErineDialog::~ErineDialog()
{delete ui;
}void ErineDialog::on_pushButton_clicked()
{if(isStarted == false){isStarted = true;m_timer =startTimer(50);ui->pushButton->setText("停止");}else{isStarted = false;killTimer(m_timer);ui->pushButton->setText("开始");}}//加载图片容器功能
void ErineDialog::loadPhotos(const QString& path)
{QDir dir(path);//便利当前目录下所欲图片QStringList list1 = dir.entryList(QDir::Files);for(int i = 0;i<list1.size();i++){QImage image(path+"/"+list1.at(i));m_vecPhotos<<image;//保存到容器}QStringList list2 = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);for(int i = 0 ;i<list2.size();i++){loadPhotos(path+"/"+list2.at(i));}
}//定时器事件处理函数
void ErineDialog::timerEvent(QTimerEvent *)
{m_index = qrand() % m_vecPhotos.size();update();
}//绘图事件处理函数
void ErineDialog::paintEvent(QPaintEvent*)
{QPainter painter(this);QRect rect = ui ->frame->frameRect();rect.translate(ui->frame->pos());painter.drawImage(rect,m_vecPhotos[m_index]);}
#ifndef ERINEDIALOG_H
#define ERINEDIALOG_H#include <QDialog>
#include <QTime>
#include <QPainter>
#include <QDir>
#include <QTime>
#include <QVector>
#include <QImage>
#include <QDebug>namespace Ui {
class ErineDialog;
}class ErineDialog : public QDialog
{Q_OBJECTpublic:explicit ErineDialog(QWidget *parent = 0);~ErineDialog();private slots:void on_pushButton_clicked();private:Ui::ErineDialog *ui;QVector<QImage> m_vecPhotos;//保存图片的容器int m_index;//图片在容器中的索引int m_timer;//定时器bool isStarted;//标记摇奖机的状态,真 正在摇奖 假 没摇奖
private://加载图片容器功能void loadPhotos(const QString& path);//定时器事件处理函数void timerEvent(QTimerEvent *);//绘图事件处理函数void paintEvent(QPaintEvent*);};#endif // ERINEDIALOG_H