QT_学习笔记
来源:互联网 发布:js date yyyymmdd 编辑:程序博客网 时间:2024/06/03 18:18
1. 在堆上用new分配的内存,为什么没有用delete释放?
从HelloQt说起
#include <qapplication.h>
#include <qlabel.h>
int main( int argc, char **argv )
{
QApplication app( argc, argv );
QLabel *label=new QLabel(“Hello QT!”,0);
app.setMainWidget( label );
label->show();
return a.exec();
}
这里label是new出来的一个指针变量,也就是在堆上申请的内存,在C++语言里,明确过,在堆上分配的内存是必须认为的用delete释放的,防止内存泄露。这里为什么没有呢。后来看到有的QT程序也有明确使用delete释放内存的。这里越发不解了。后来,查到原来是QT扩展了C++,如果指针对象有父对象时,可以不用显式释放内存。我们需要显式释放的是那些没有父对象的孤立的指针。但上面这个例子并没有继承父对象,注意第二个指针,指向父对象的指针参数为0,即没有父对象,但是setMainWidget把它设为了主窗口部件,它就和程序同步了,当程序退出的时候自动释放,孩子对象的释放也是如此,在QT中扩展了C++ ,如果父亲对象无效时,子对象自动释放分配的内存。
2. 关于前置声明的说明
前置声明是C++ 的一个特性,不过我是在学QT时才接触到。这里有一些说明。
#include <qapplication.h>
class QCheckBox;
class myClass:public QDialog
{
Q_OBJECT
public:
--------
signals:
---------
private:
QCheckBox *myCheck;
};
这里定义了一个示例类,继承于QDialog,其中用Q_OBJECT宏是因为声明的类定义了自己的signals,其中第二行就是一种前置声明,因为私有成员里用到了此类,这种方法比#include <qcheckbox.h>编译速度要快,注意私有成员为一个指针,如果是个私有对象而不是指针的话就不能用这种前置声明。具体的理由可以参考C++关于前置声明的说明,这里只是一个提醒
以上两点参考: 1,2两点源文引用,感谢原作者
3. 控件内存释放
Qt中,如果申明了两个数组:
QLabel *label[8];
QLabel *sLabel[8];
这两个都是QLabel类型的指针数组,希望在以后的使用中动态的分配其内存;
那么就应该:
在class MyLabel中...
for(int i=0;i<8;i++)
{
label[i] = new QLabel("This is a Label",this,0);
//申请空间.
sLabel[i] = new QLabel("",label[i],0);
//第二个Label指针数组的父对象为上面申请过空间的Label.
}
QLabel的构造函数的原形为:
QLabel ( const QString & text, QWidget * parent, const char * name = 0, WFlags f = 0 )
text: Label上要显示的字符串;
parent: Label的父对象的指针;
name: Label的名字;
f: Label的Flags;
从上面的代码容易得知label数组每个元素是以当前MyLabel类对象为父对象的;而sLabel里的元素是以对应的label为父对象的;
在MyLabel的析构函数中就有相应的释放空间的代码:
1 for(int i=0;i<8;i++)
2 {
3 delete label[i];
4 //delete sLabel[i];
5 }
这里要是不注释掉上面第4行的语句就会出现段错误,原因经过查找资料得知在Qt中如果在创建组件对象时设置了父对象时,由父对象负责释放其子对象的空间.所以上面第2行已经释放了label的空间,而其子对象的sLabel也随之被释放,所以如果第三行再进行释放就会出现之前所说的错误.
Qt虽然提供了这种机制,自动回收部分的内存,但是自己写程序的时候还是要小心,不要造成内存泄漏,这对于嵌入式的应用来说更加是件重要的事.毕竟现在的嵌入式硬件还是内存较小,而且要求程序可以长期稳定,高效节能的运行.
第三点参考: 原文链接,感谢原作者
4. 关于QLineEdit输入为ip格式时的验证和错误提示
(1).输入时需要验证是否符合ip的输入格式
QRegExp regx("^(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)\\.(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)\\.(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)\\.(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)"); QValidator *validator = new QRegExpValidator(regx,displays_ledit[i]);//输入验证 displays_ledit[i]->setValidator(validator);
(2).输入完后,点击保存或类似操作时,需要对输入的信息进行检查,因为如果没有输入完,或者其他
bool ConfigScreenUI::checkIP(){bool flag = true;//检测ip地址格式QRegExp rx2("^(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)\\.(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)\\.(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)\\.(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d)");for (int i = 0; i < 10; i++){if ( displays_ledit[i]->text() == "")//可以允许不输入,这里看自己需求continue;else if ( !rx2.exactMatch(displays_ledit[i]->text().trimmed()) ) //判断ip是否符合表达式{warning_lab[i]->setText("IP格式错误");flag = false;}else{if(warning_lab[i]->text() == "IP格式错误"|| displays_ledit[i]->text() == "")warning_lab[i]->setText("");}}if (flag == false)return flag;//检测ip冲突,如果需要输入很多个ip(通过多个QLineEdit),检测是否重复,可以通过下面的方法QMap<QString, int> map;QMap<QString, int>::iterator i_IP;map.clear();for (int i = 0; i < 10; i++){i_IP = map.find( displays_ledit[i]->text().trimmed() );if ( i_IP == map.constEnd() ){if (warning_lab[i]->text() != "")map.insert(displays_ledit[i]->text().trimmed(), i+1);//没有找到就插入数据if(warning_lab[i]->text() == "IP地址冲突" || displays_ledit[i]->text() == "")warning_lab[i]->setText("");}else{warning_lab[i]->setText("IP地址冲突");warning_lab[i_IP.value()-1]->setText("IP地址冲突");return false;}}return true;}
5. 简单对话框输出信
QMessageBox::information(this, "标题提示文字","内容提示文字");
6.信号量机制
bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method,Qt::ConnectionType type = Qt::AutoConnection ) [static]
sender:发送方,表示是谁发出的这个信号(这个就是signals)
signal:发送的信号类型,发送的那种信号,这个信号肯定是从属于sender类对象的
receiver:接收方,表示这个信号应该由谁来接收
method:接收信号后要执行的方法(这个就是slots),这个槽也是从属于receiver的
(1) 在类中定义一个槽slots,来使用已经定义好的信号
例如:实现,当点击按钮时,弹出一个框,上面说"恭喜你打开了我"
//类中声明
class Say
{
protected slots:
void sayWordSlot(); // 为一个按钮定义一个槽
}
//类外定义
void Say::sayWordSlot()
{
QMessageBox::information(this, "这是Say类里面的","恭喜你打开了我");
}
//类外使用
QToolButton *say_btn = new QToolButton(this);
connect(say_btn, SIGNAL(clicked()), this, SLOT(sayWordSlot() ) );//当点击按钮,就触发本页面的sayWordSlot方法
(2)自定义处理信号和处理方法
class Number
{
public :
int GetNumber();
private:
int number;
protected slots:
void changeNumberSlot(); // 为一个按钮定义一个槽
signals:
void numberChangeSignal(); //自定义一个信号
};
//类外定义
int Number::GetNumber()
{
return number;
}
void Number::changeNumberSlot()
{
number = 0; //只要大于100就置为0,随便确定的需求
}
Number *num = new Number();
connect(num, SIGNAL( numberChangeSignal()), num, changeNumberSlot() );
//测试触发
if (num->GetNumber() > 100)
emit numberChangeSignal();
小帮助:
emit的理解参考: http://www.qkevin.com/archives/89
7. 关于控制位置的几个基本方法的理解
(1).
voidmove ( int x, int y )如果是窗体,(x,y) 坐标参数是屏幕坐标
如果是控件,(x,y) 坐标参数是窗体内坐标
这个方法,可以用于所有QWidget的移动,但是如果它属于某一个部件,那么它的位置就会有限制,不能移出它的控件位置
(2).
void QWidget::setContentsMargins ( int left, int top, int right, int bottom )
left,top,right,bottom : 表示上下左右的间隔,这个方法使用的前提,一般为:界面大小,位置都固定,不会变动,可以考虑用,如果是自适应的,最好用设置比例的方法来控制位置
8. 用于绘制的两个常用方法:
void paintEvent(QPaintEvent *);//这个方法在对象创建,update···等,会被调用,可以用于一些划线,画矩形框等
void showEvent(QShowEvent *); //这个在显示时候就会被调用,可以用于界面初始数据的提取时,在此方法中初始化一些数据
//每一个QWidget都有这个方法
例如:
void A::paintEvent(QPaintEvent *)//A表示一个类
{
if(this == NULL)
return;
QPainter painter(this);
painter.setPen(QColor("#bfbfbf"));
painter.setBrush(QBrush(QColor("#e6e6e6")));
painter.drawRect(51, 32, 1455, 817);//画矩形框
}
9. 字体的设置
QFont ftt("微软雅黑", 12);
QLabel *m_lab = new QLabel();
m_lab->setFont(ftt);
//小提示:
m_lab->setStyleSheet("QLabel{color:red}");//也可以用qssl来实现
额外:
int m_count = 4;
QString q_str = QString("共 <font color = #bf0000>%1</font> 张床").arg(m_count);
m_lab->setText(q_str);
10. 自定义按钮实现(点击是出现下划线)
(1).下划线按钮
定义
//Underline.h#ifndef UNDERLINEBTN_H#define UNDERLINEBTN_H#include <QWidget>#include <QToolButton>#include <QPainter>#include <QPixmap>#include "ui_UnderlineBtn.h"class UnderlineBtn : public QToolButton{Q_OBJECTpublic:UnderlineBtn(QString text, int width, int hight, int font_size, QWidget *parent = 0);~UnderlineBtn();void changeState();private:Ui::UnderlineBtn ui;QString m_text;QString m_text_color;bool m_is_selected;int m_width;int m_hight;int m_font_size;private:void paintEvent(QPaintEvent *);};#endif // UNDERLINEBTN_H
实现
//Underline.cpp#include "UnderlineBtn.h"UnderlineBtn::UnderlineBtn(QString text, int width, int hight,int font_size, QWidget *parent): QToolButton(parent){ui.setupUi(this);setCursor(QCursor(Qt::PointingHandCursor));//鼠标移入时变手形//设置用户定义的属性m_text = text;m_width = width;m_font_size = font_size;m_hight = hight;setFixedSize(m_width,m_hight);m_is_selected = false;setEnabled(true);m_text_color = "#0e0e0e";}UnderlineBtn::~UnderlineBtn(){}void UnderlineBtn::paintEvent(QPaintEvent *){if(this == NULL)return;QPainter painter(this);painter.setFont(QFont("微软雅黑", m_font_size));painter.setPen(QColor(m_text_color));//设置文字颜色painter.drawText(0, 0, m_width, m_hight, Qt::AlignLeft, m_text);//绘制文字if(m_is_selected){painter.drawLine(0,m_hight-5,m_width,m_hight-5);//在文字的下方画一条线}}//改变状态void UnderlineBtn::changeState(){if(m_is_selected){m_is_selected = false;setEnabled(true);m_text_color = "#0000ff";update();}else{m_is_selected = true;setEnabled(false);m_text_color = "#0e0e0e";update();}}
(2). 画图按钮
定义
//PictureBtn.h#ifndef PICTUREBTN_H#define PICTUREBTN_H#include <QToolButton>#include "ui_PictureBtn.h"class PictureBtn : public QToolButton{Q_OBJECTpublic:PictureBtn(QString picture_normal, QString picture_selected, QString file_dir, QString text, QWidget *parent = 0);~PictureBtn();void changeState();private:Ui::PictureBtn ui;QString m_normal_pic;QString m_picture_dir;QString m_icon_dir;QString m_text;QString m_text_color;bool m_is_selected;private:void paintEvent(QPaintEvent *);void enterEvent(QEvent *);void leaveEvent(QEvent *);};#endif // PICTUREBTN_H
实现
//PictureBtn.cpp#include "PictureBtn.h"#include <qpainter.h>#include <qpixmap.h>PictureBtn::PictureBtn(QString picture_normal, QString picture_selected, QString file_dir, QString text, QWidget *parent): QToolButton(parent){ui.setupUi(this);m_normal_pic = picture_normal;m_picture_dir = picture_selected;m_icon_dir = file_dir;m_text = text;setCursor(QCursor(Qt::PointingHandCursor));//鼠标移入时变手形QPixmap pic(picture_selected);setFixedSize(pic.size());m_is_selected = false;setEnabled(true);m_text_color = "#0e0e0e";}PictureBtn::~PictureBtn(){}void PictureBtn::paintEvent(QPaintEvent *){if(this == NULL)return;QPainter painter(this);QPixmap background;background.load(m_picture_dir);int x = 0, y = 0, w = 0, h = background.height();if(m_is_selected){painter.drawPixmap(0, 0, background.width(), background.height(), background);} if(m_icon_dir != ""){QPixmap icon(m_icon_dir);painter.drawPixmap(18, (background.height() - icon.height())/2, icon.width(), icon.height(), icon);x = icon.width() + 8;w = background.width() - icon.width() - 5;} else{w = background.width();}painter.setPen(QColor(m_text_color));if(m_icon_dir == "")painter.setFont(QFont("微软雅黑", 13));elsepainter.setFont(QFont("微软雅黑", 15));//绘制文字painter.drawText(x, y, w, h, Qt::AlignCenter, m_text);}void PictureBtn::changeState(){if(m_is_selected){m_is_selected = false;setEnabled(true);update();}else{m_is_selected = true;setEnabled(false);m_text_color = "#0e0e0e";update();}}void PictureBtn::enterEvent(QEvent *){if(!m_is_selected){m_text_color = "#0000ff";update();}}void PictureBtn::leaveEvent(QEvent *){if(!m_is_selected){m_text_color = "#0e0e0e";update();}}
//使用实例
PictureBtn *m_btn = new PictureBtn("图片方式", "图片路径", “图标路径”, "按钮上面的字", "父部件");
11. 数据库操作
#define ret_type int#define RET_OK 0#define RET_FAIL 1ret_type DBBasic::connect(QSqlDatabase &db){db = QSqlDatabase::addDatabase("QMYSQL", QUuid::createUuid());//连接数据库的配置信息db.setHostName("ip地址");db.setUserName("数据库用户名");db.setPassword("数据库密码");db.setDatabaseName("数据库名称");if ( ! db.open() ) {handleError( db.lastError(), db );return RET_FAIL;}QSqlQuery query(db);if ( ! query.exec("set names 'utf8'") ) {handleError( query.lastError(), db );return RET_FAIL;}return RET_OK;}ret_type DBBasic::execute(const QString query_str, QSqlQuery &sql_query, QSqlDatabase &db){QSqlQuery query(db);if ( ! query.exec(query_str) ) {handleError(query.lastError(), db);return RET_FAIL;}sql_query = query;return RET_OK;}ret_type DBLogic::test(QSqlQuery &query){ret_type ret = RET_OK;QString query_str;QSqlDatabase m_conn;//初始化query.clear();query_str = QString("sql语句");DBBasic::connect(m_conn);ret = DBBasic::execute(query_str, query, m_conn);//query为执行得到的结果if(ret!= RET_OK) {return RET_FAIL;}//一条一条处理执行结果(当用select来执行的时候),这里看自己需求)while (query.next()){ //QString title = query.value(0).toString(); //int year = query.value(1).toInt(); //std::cerr << qPrintable(title) << ": " << year << std::endl;}return RET_OK;}
以上数据库代码,只是使用的基本方式,不一定能满足所有要求,
可以再参考右边网址来使用: Qt数据库总结
12. 弹出自定义窗口的实现
//窗口的类型
typedef enum _window_style {
WIND_CL_ONE_BUTTON = 700,
WIND_CL_DOUBLE_BUTTONS,
WIND_CL_NO_BUTTONS,
WIND_CONFIRM,
WIND_FAILED,
WIND_SUCCESS,
WIND_INFO
}window_style;
//基类:
//BaseWind.h#ifndef BASEWIND_H#define BASEWIND_H#include <QDialog>#include <QPoint>#include <QString>#include <QPainter>#include <QKeyEvent>#include "ui_BaseWind.h"//这里可能会有一些宏定义,所以根据你的需求自己确定class BaseWind : public QDialog{Q_OBJECTpublic:BaseWind(const int width, const int height, const QString title, QWidget *parent = 0);~BaseWind();protected:void setValidSize(const int min_width, const int min_height);void keyPressEvent(QKeyEvent *event);//屏蔽回车键private:Ui::BaseWind ui;protected:int m_width, m_height;//窗口的宽、高int m_relative_x, m_relative_y;//窗口的相对坐标QString m_title;//窗口的标题protected slots:void windowClose();void okButtonClicked();};#endif // BASEWIND_H
//BaseWind.cpp#include "BaseWind.h"BaseWind::BaseWind(const int width, const int height, const QString title, QWidget *parent): QDialog(parent){ui.setupUi(this);m_width = width;m_height = height;m_title = title;this->setFixedSize(m_width + 2, m_height + 2);//给窗口的边缘多留1个像素,否则窗口的边缘的线很细//裁剪对话框,去掉标题、按钮及边框this->setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);//设置窗口为模态显示this->setModal(true);}BaseWind::~BaseWind(){}void BaseWind::setValidSize(const int min_width, const int min_height){if(m_width < min_width)m_width = min_width;//限定窗口宽的最小值if(m_height < min_height)m_height = min_height;//限定窗口高的最小值m_relative_x = 1;//给窗口的边缘多留1个像素,否则窗口的边缘的线很细m_relative_y = 1;}void BaseWind::keyPressEvent(QKeyEvent *event){if(event->key() == Qt::Key_Return){return;}}void BaseWind::windowClose(){this->hide();}void BaseWind::okButtonClicked(){emit accepted();}
//继承基类,派生类的实现
#ifndef AUTOCLOSEWIND_H#define AUTOCLOSEWIND_H#include "BaseWind.h"#include "ui_AutoCloseWind.h"class AutoCloseWind : public BaseWind{Q_OBJECTpublic:AutoCloseWind(const window_style style, const int width, const int height, const QString content, QWidget *parent = 0);~AutoCloseWind();private:void paintUI();void paintEvent(QPaintEvent *);private slots:void windowClose();private:Ui::AutoCloseWind ui;window_style m_style;//窗口的类型QString m_content;//提示的内容};#endif // AUTOCLOSEWIND_H
//AutoCloseWind.cpp#include "AutoCloseWind.h"#include <QTimer>AutoCloseWind::AutoCloseWind(const window_style style, const int width, const int height, const QString content, QWidget *parent): BaseWind(width, height, "", parent){ui.setupUi(this);m_style = style;m_content = content;paintUI();}AutoCloseWind::~AutoCloseWind(){}void AutoCloseWind::paintUI(){this->setValidSize(120, 40);//设置窗口的宽最小为120,高最小为40QTimer::singleShot(1500, this, SLOT(windowClose()));//窗口1.5秒后消失}void AutoCloseWind::paintEvent(QPaintEvent *){if(this == NULL)return;QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);//防止曲线锯齿//画背景painter.setBrush(QColor("#f6f6f6"));painter.setPen(QColor("#a0a0a0"));painter.drawRoundedRect(m_relative_x, m_relative_y, m_width, m_height, 2, 2);//画图标QPixmap icon;if(m_style == WIND_SUCCESS)icon.load(SUCCESS_ICON);else if(m_style == WIND_INFO)icon.load(INFO_ICON);painter.drawPixmap(m_relative_x + 10, m_relative_y + (m_height - 24)/2, 24, 24, icon);//设定图标的大小为:24*24//画文字QFont content_font("微软雅黑", 13);painter.setFont(content_font);painter.setPen(QColor("#404040"));painter.drawText(m_relative_x + 45, m_relative_y, m_width - 55, m_height, Qt::AlignLeft | Qt::AlignVCenter, m_content);}void AutoCloseWind::windowClose(){this->hide();delete this;}
13. 图片大小转换
QPixmap map("图片路径");
QPixmap set_map = map.scaled("宽", “高',Qt::IgnoreAspectRatio); //Qt::KeepAspectRatio:这种方式为保持比例
14. 窗口置顶的问题
(1).让QMainWindow窗口在QDialog窗口上面置顶层,默认是置QDialog窗口的底层
setWindowFlags(Qt::Dialog);
或者
子窗口名:userManagerDialog
Qt::WindowFlags flags = Qt::Dialog;
userManagerDialog->setWindowFlags(flags);
(2).弹出子窗口时禁用主窗口
userManagerDialog->setWindowModality(Qt::ApplicationModal); //阻塞除当前窗体之外的所有的窗体
- QT_学习笔记
- QT_内存
- QT_渐变填充
- Qt_程序启动画面
- QT_后台输出
- QT_编程基础
- Qt_套接字
- Qt_翻译小工具
- qt_简易记事本_1
- qt_简易记事本_2
- qt_简易记事本_3
- qt_简易记事本_4
- qt_简易记事本_5
- qt_简易记事本_6
- qt_简易记事本_7
- Qt_几个错误
- Qt_类型转换
- QT_放大与缩小按钮
- url传递的参数值中包含&时,url自动截断问题解决
- 排序算法总结
- tomcat加载项目理解
- Did you know ?
- ORACLE分析函数(2)
- QT_学习笔记
- 【Apache Kafka】设计理念浅析
- linux
- QT学习笔记之 IconEditor
- Lync 2013移动客户端支持差异
- linux互传文件scp
- 特定场景的Cralwer
- K近邻算法
- Cow Tours