Qt知识点梳理与踩过的坑
一、杂记
//管理整个应用程序所用到的资源QApplication a(argc, argv);
///将应用程序的控制权传递给Qt,程序进入事件循环,等待鼠标,键盘等事件
return a.exec();
///这句初始化静态窗体,内部建立所需要的信号和槽对应
ui->setupUi(this);
img = img.rgbSwapped(); //BGR 转RGB
rightTip->setAlignment(Qt::AlignCenter | Qt::AlignRight);//对齐方式
//获得当前程序所在目录
return QApplication::applicationDirPath();
//设置图标
this->setWindowIcon(QIcon(":/16-9/LOGO.png"));
//设置外部字体
nIndex = QFontDatabase::addApplicationFont(path + QStringLiteral("/微软vista雅黑.ttf"));
if (nIndex != -1)
{
QStringList strList(QFontDatabase::applicationFontFamilies(nIndex));
if (strList.count() > 0)
{
font.setFamily(strList.at(0));
font.setPixelSize(FONT_SIZE *scale * 90 / 72);
}
}
//设置style
m_centralWidget->setStyleSheet("QWidget#centralWidget{background-color:rgb(242, 242, 242,180)};");
//管理多个信号对应同一个槽,很好用
QSignalMapper signalMapper;
for(int i=0;i<btn_count;i++)
{
signalMapper.setMapping(btn_custom+i,i);
connect(btn_custom+i,SIGNAL(clicked(bool)),&signalMapper,SLOT(map()));
}
connect(&signalMapper,SIGNAL(mapped(int)),this,SLOT(onToolAction(int))); //设置窗体透明,在没有父窗口的情况下可以生效,不会显示黑色。
leftDownBox->setWindowFlags(Qt::FramelessWindowHint);
leftDownBox->setAttribute(Qt::WA_TranslucentBackground);
//遍历父窗口上的子控件
QList<CustomToolBtn*> Widgets = customBtnWidget->findChildren<CustomToolBtn*>();
if(!Widgets.isEmpty())
{
foreach(CustomToolBtn* obj ,Widgets)
{
delete obj;
}
}
//打开窗口获取文件或者文件夹路径
QStringList filePath;
QFileDialog *fileDialog = new QFileDialog(this);
fileDialog->setWindowTitle(tr("Open Image"));
fileDialog->setFileMode(QFileDialog::ExistingFiles);
fileDialog->setDirectory(".");
fileDialog->setNameFilter("*.png *.bmp *.jpg");
if(fileDialog->exec() == QDialog::Accepted)
{
filePath = fileDialog->selectedFiles();
// QMessageBox::information(NULL, tr("Path"), tr("You selected ") + path);
}
//程序只能启动一个
QSharedMemory shared("name");//随便填个名字就行
if (shared.attach())
return 0;
shared.create(1);
//线程 例子
MovieShow::MovieShow(QObject *parent) : QThread(parent)
{
m_mMovie = NULL;
m_bstop = true;
obj = parent;
}
MovieShow::~MovieShow()
{
if(m_mMovie!=NULL)
{
m_mMovie->stop();
delete m_mMovie;
m_mMovie = NULL;
}
endMovie();
quit();
terminate();
//wait();
}
void MovieShow::startMovie()
{
QMutexLocker mutex(&mtx);
m_bstop = false;
if(NULL!=m_mMovie)
{
m_mMovie->start();
count = 0;
}
this->start();
}
void MovieShow::endMovie()
{
QMutexLocker mutex(&mtx);
m_bstop = true;
}
void MovieShow::setMovie(const QString &path)
{
m_strPath = path;
if(NULL == m_mMovie)
{
m_mMovie = new QMovie(m_strPath);
}
}
QPixmap& MovieShow::getCurrentPix()
{
return m_mMovie->currentPixmap();
}
void MovieShow::run()
{
while(1)
{
QPixmap pix = m_mMovie->currentPixmap(); ;
msleep(500);
emit sendCurrentPix(QPixmap(pix));
if(m_bstop)
{
break;
}
}
}
///在静态的界面里修改了控件的一些属性,需要重新构建才会起作用,如果发现没有修改,重新构建下或许能解决问题
二、父子机制与布局管理
///当使用布局的时候,没有必要显式的指定父窗口,布局会自动设置父窗口
Qt的父子对象机制是在QObject中实现的。当利用一个父对象创建一个子对象(QLabel *label = QLabel(this);)父对象会把这个子对象添加到自己的子对象列表中去,见上图。当删除这个父对象时,它会遍历子对象列表并且删除每一个子对象。然后,这些子对象再去 删除它们包含的子对象列表中的对象。如此反复递归调用,直至清空所有对象为止。这种父子对象机制可在很大程度上简化内存管理工作,降低内存泄漏的风险。没有指定父对象的需要手动删除
(如果在删除父对象之前删除了子对象是可以的,父对象会自动把删掉的子对象从列表中移除,但是删除了父对象后再去删除子对象就会出错,因为子对象已经被删掉了)
记:在开发中各种情况都可能遇到,有的时候删除了父对象,还会报其他错误(内存泄漏什么的),所以就手动一层层删。有的时候改的多了,程序关上会报内存错误,重新构建就没事了,当然以上说的都是windows平台,切记多执行qmake多重新构建构建。
布局管理:当子控件隐藏或者动态删除或者又show的时候,也能自动适应
QSizePolicy的 Preferred Expanding策略
Preferred:窗口部件的默认大小就是它比较合适的大小,但是如果需要,还是可以对该窗口部件进行拉伸或者压缩
Expanding:是可以拉伸或者压缩该窗口部件,并且希望他能变长变宽。
多出来的窗口空间会分配给Expanding窗口部件,而preferred窗口部件不变。
影响布局的方式:
1.布局拉伸因子:setstretch()
2.margin
3.space
4.子窗口部件的最小大小,最大大小或固定大小,当布局管理器在摆放这些窗口部件的时候,它就会考虑这些约束条件
5.对子窗口部件的类进行派生并且重新实现sizeHint()函数,由此获得所需的大小。
三、信号与槽
///信号槽必须的Q_OBJECT
///signals关键字实际上是一个宏,C++预处理器会在编译程序找到它之前转为标准c++代码
///同理slots也是
///槽和普通c++成员函数几乎一样,可以是虚函数,可以被重载,可以是public protected private/// 也可以直接被其它成员函数调用,参数可以是任意类型。唯一不同,槽函数可以和信号连接,每当发射信号,
/// 对应的槽函数会自动执行
/// 一个信号可以连接多个槽
/// 多个信号可以连接同一个槽
/// 一个信号可以与另一个信号连接
/// 连接可以被移除 disconnect
/// 要使信号和槽成功链接,它们的参数必须具有相同的顺序和相同的类型
/// (如果信号参数比它连接的槽的参数多(其他都符合规则)那么多余的参数会被简单的忽略掉)
/// connect(sender,SIGNAL(signal(int)),receiver,SLOT(slot(int val)); 这样是错误的,要把参数名删掉 否则报错找不到对应的槽
四、处理密集时响应保持
1.多线程:在线程里处理耗时操作(文件读写,但是不能刷新界面),然后通过信号槽的方式,通知主线程刷新界面
2.
QCoreApplication::processEvents();
或者qApp->processEvents(); 这个函数告诉主线程处理那些还没有被处理的 各类事件,然后再将控制权返回给调用者。
实际上QApplication::exec();就是一个不断调用processEvents的循环过程。
五、事件
事件发生的先后顺序:
1.子类化QApplication并且重新实现notify()
2.在QApplication对象中安装事件过滤器
3.在QObject中安装事件过滤器
4.重新实现QObject::event()
5.重新实现某些特定的事件(mousePressEvent,paintEvent等)
处理ocx控件的windows,查了好久才查到。
qApp->installNativeEventFilter(liveDetectWdg);
bool LiveDetect::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
//捕捉ocx发送的自定义消息
MSg *param = static_cast<MSg *>(message);
if(param && param->message<=1828 && param->message>=1824)
{
emit sendUserMessage(param->message);
}
//当窗口关闭的时候,发送个1827结束下事件循环
if(param->message == 16)
{
emit sendUserMessage(1827);
}
/*switch (param->message)
{
case 1824:
{
}
break;
case 1825:
{
}
break;
}*/
return false;
}
六、跨平台
#ifdef Q_OS_WIN
#define WINAPI __stdcall
#define IDCardDLLSO "xxx.dll"
#define UpLoadDLLSO "yyy.dll"
#endif
// Linux上的代码
#ifdef Q_OS_LINUX
#define UNICODE
#define WINAPI
#define IDCardDLLSO "./xxx.so"
#define QStringToTCHAR Qstr2lpc
#endif
// Mac上的代码
#ifdef Q_OS_MAC
#endif
#define LPCWSTR const wchar_t*
#define LPWSTR wchar_t*
#ifdef UNICODE
typedef wchar_t TCHAR;
#define WINAPI __stdcall
#define LPCTSTR const wchar_t*
#define LPTSTR wchar_t*
#else
typedef char TCHAR;
typedef const char* LPCTSTR;
typedef char* LPTSTR;
#endif
#define _T QStringLiteral
#ifdef UNICODE
#define QStringToTCHAR(x) (wchar_t*) x.utf16()
#define PQStringToTCHAR(x) (wchar_t*) x->utf16()
#define TCHARToQString(x) QString::fromUtf16((x))
#define TCHARToQStringN(x,y) QString::fromUtf16((x),(y))
#else
#define QStringToTCHAR(x) x.local8Bit().constData()
#define PQStringToTCHAR(x) x->local8Bit().constData()
#define TCHARToQString(x) QString::fromLocal8Bit((x))
#define TCHARToQStringN(x,y) QString::fromLocal8Bit((x),(y))
#endif
暂时先写这么多,往细节地方写,根本写不完。。。