Qt 小知识总结

7 篇文章 2 订阅

简述:

Qt 官网下载地址: http://download.qt.io/archive/qt/


1、关于 Qt触摸事件


需要确定两点:A . 设备支持touch事件(是触控设备)

B . 需要设置窗口属性setAttribute ( QT::WA_AcceptTouchEvents ) ; // 接收touch消息


2、setMouseTrack ( );


要想实现 mouseMoveEvent ,则需要在构造函数中添加setMouseTrack (true) , 直接得到监听事件,若是 setMouseTrack (false) ,只有在鼠标按下才会有 mouseMoveEvent 监听事件响应。


3、Qt中OpenGL的简单介绍


Qt中的OpenGL主要是在QGLWidget类中完成的,而要使用QtOpenGL 模块,需要在项目文件 .pro 中添加代码:

    QT += opengl
    win32:LIBS += -lOpengl32 \
                -lglu32 \
                -lglut

QGLWidget 类是一个用来渲染OpenGL图形的部件,提供了在Qt中显示OpenGL图形的功能。这个类使用起来很简单,只需要继承该类,然后像使用其他QWidget部件一样来使用它。QGLWidget提供了3个方便的纯虚函数,可以在子类中通过重新实现它们来执行典型的OpenGL任务:

initializeGL ( ) : 设置OpenGL渲染环境,定义显示列表。该函数只在第一次调用 resizeGL ( )paintGL ( ) 前被自动调用一次。

resizeGL ( ) : 设置OpenGL的视口、投影等。每次部件改变大小时会自动调用该函数。

paintGL ( ) :渲染OpenGL场景。每当部件需要更新时会调用该函数。

也就是说,Qt中当创建并显示出一个QGLWidget子对象时,会自动依次调用initializeGL ( ) 、resizeGL ( ) 、 paintGL ( ),完成当前场景的绘制;而当某些情况发生时,会根据情况决定是否自动调用initializeGL ( ) 、resizeGL ( ) ,一旦调用了initializeGL ( ) 、resizeGL ( ) ,会紧跟着调用paintGL ( ) 对场景进行重新绘制。


4、renderText  ( ): 在OpenGL 图形周围写字 


头文件:qgl.h

函数原型:

    void renderText(int x, int y, const QString & str,
                    const QFont & fnt = QFont());
    void renderText(double x, double y, double z, const QString & str,
                    const QFont & fnt = QFont());
x , y , z :显示文字的坐标位置;str : 要显示的字符串;fnt :显示文字的字体


5、获取系统屏幕分辨率


const QRect QDesktopWidget::screenGeometry(int screen = -1) const

其中的参数就是显示器的id,默认是-1,如果是多个显示器,则显示器编号依次为0(主显示器),1,2,3...( 这些编号和设置里看到的编号没有关系)




① 如图,这是目前的显示设置情况,其中标识为2的显示器是主显示器,1则是扩展显示器。而实际上,通过

QDesktopWidget * deskTop = QApplication::desktop();
int curMonitor = deskTop->screenNumber ( this ); // 参数是一个QWidget*

获得到的当前所在屏幕的编号来看,设置中标识为2的实际上是0,标识为1的实际是1。

② 当获取到显示器编号后,就可以通过下面语句来获取当前所在屏幕的分辨率


QRect rect = desktop->screenGeometry(curMonitor);


③ 这时rect.width rect.height 就是当前屏幕的分辨率了。而rect.x和rect.y是什么呢?回到上图,可以用上面的函数获取主(编号为2的)显示器rect.x和rect.y,会发现 rect.x=0,rect.y=0 。可见,整个显示器“坐标”是以主显示器左上角为(0,0)点的。在扩展(此处编号为1的)显示器获得到的 rect.x=-1366,rect.y=161说明这个就是那个扩展显示器左上角的坐标了。那么就可以通过这个来计算所需要的屏幕坐标了。

④ 示例:


m_settings->show();
m_settings->raise();
int screenBottom = 
        QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(m_settings)).bottom();
QPoint position = ui->settingsButton->mapToGlobal(QPoint(0, ui->settingsButton->height()));
m_settings->move(position);
QRect settingsRect = m_settings->geometry();
settingsRect.setHeight(680);
if(settingsRect.bottom() > screenBottom ){
       int diff = settingsRect.bottom() - screenBottom;
       settingsRect.setHeight(settingsRect.height() - diff);
}
m_settings->setGeometry(settingsRect);


6、保存图片


① 将当前场景渲染为像素图

可使用 renderPixmap() 将当前场景渲染为像素图。帧缓冲的内容可使用 grabFrameBuffer() 进行捕获。

renderPixmap() grabFrameBuffer() 的主要差别就是使用 renderPixmap() 时不捕捉叠置

QPixmap pixmap = ui->orthoDrawWidget->renderPixmap(0, 0, true);


② 初始化图片名为当前时间

QString defaulName = QString("/") +
            QDateTime::currentDateTime().toString("yyyy_MM_dd_HH_mm_ss_zzz") +
            ".png";


③ 打开文件保存对话框,并设置图片名

QString filename = QFileDialog::getSaveFileName(
                this,
                tr("Save snapshot"),
                QDir::currentPath() + defaulName,
                tr("PNG file (*.png)"));


④ 如果图片名不为空保存图片

    if (!filename.isNull()) {
        QFileInfo fi(filename);
        QDir::setCurrent(fi.absolutePath()); //设置应用程序的当前工作目录为fi.absolutePath()

        pixmap.save(filename);
    }


⑤ 由上,可得

void ViewerPlugin::orthoSnapshot()
{
    //使用renderPixmap() 将当前场景渲染为像素图。
    QPixmap pixmap = ui->orthoDrawWidget->renderPixmap(0, 0, true);
    QString defaulName = QString("/") +
            QDateTime::currentDateTime().toString("yyyy_MM_dd_HH_mm_ss_zzz") +
            ".png";
    QString filename = QFileDialog::getSaveFileName(
                this,
                tr("Save snapshot"),
                QDir::currentPath() + defaulName,
                tr("PNG file (*.png)"));
    if (!filename.isNull()) {
        QFileInfo fi(filename);
        QDir::setCurrent(fi.absolutePath()); //设置应用程序的当前工作目录为fi.absolutePath()

        pixmap.save(filename);
    }
}


7、virtual void print()const = 0;


(1=0 说明它是纯虚函数

(2const表明不能修改其数据成员

const和 =0 没有关系,要分开理解。

成员函数后面用 const 修饰,通俗的理解就是在这个函数内不能修改类的成员变量,除非那个成员变量是mutable 的。

=0 表示这个成员函数是纯虚函数,也就是它可以没有定义,只有接口,由它的继承类具体定义它的行为,当然,也可以给它定义缺省的函数体

一个类里如果包含=0 纯虚函数,那么这个类就是一个抽象类,它不能具体实例化(不能创建它的对象),而只能由它去派生子类


8、动态加载插件库


Qt 的插件系统中通过 QPluginLoader类来动态加载插件库

A.  QPluginLoader 在后台是通过 QLibraryPrivate类完成加载库操作的,这与 QLibrary 类是一样的;

B.   多个 QPluginLoader 的实例若加载同一个插件库,则其后台的库是同一个,即是说多个 QPluginLoader 的实例并不会导致同一个动态库被多次加载;

C.   在 QPluginLoader 对象被析构时,其加载的动态库也不会被卸载

D.  QPluginLoader load 函数会在执行 instance时自动执行,一般不需要直接执行;

E.   卸载插件需要调用 unload 函数执行,但若有多个实例加载(load)了同一个插件库,那么只有在最后一个实例执行unload后才能将动态库卸载,前几个实例的 unload 方法都会返回 false ,动态库也不会被卸载。

void loadPlugin(CameraPluginStruct& p)
{
    p.pluginLoader = new QPluginLoader(p.filePath);
    p.pluginLoader->load();

    QObject* possiblePlugin = p.pluginLoader->instance(); //QPluginLoader.instance();

   if(possiblePlugin) 
   {
       // cast from QObject to correct type:
       p.plugin = qobjectcast<CameraPluginInterface>(possiblePlugin);
   }
}


void unloadPlugin(CameraPluginStruct& p)
{
    p.pluginLoader->unload();  // QPluginLoader.unload(); 
    p.pluginLoader->~QPluginLoader();

    p.pluginLoader = nullptr;
    p.plugin = nullptr;
 }



9、 QSortFilterProxyModel : 排序与过滤


QSortFilterProxyModel是用来排序和过滤的,不能单独使用,它只是一个“代理”,真正的数据需要QAbstractTableModel提供。


    QSortFilterProxyModel *sorter = new QSortFilterProxyModel(this);
    sorter->setSourceModel(m_model); //设置sorter的源模型为m_model
    m_tableView->setModel(sorter);
    m_tableView->setSortingEnabled(true); //true,使用排序

    sorter->setFilterKeyColumn(0); //设置过滤源模型内容的键的列号
    sorter->setFilterRegExp(regExp); //设置过滤源模型的内容regExp


10、void QWidget::raise ()


这个窗口部件升高到它的父窗口部件的栈的顶部

如果在屏幕上有与这个窗口部件重叠的兄弟,这个窗口部件将在它后来的这些兄弟之前变的可视了。


11、 安装源码


在安装Qt 的时候有一个选项默认不打勾的,而这个默认不安装的选项就是 Source Components (源码),安装时打上勾就可以安装源码了。安装完后,打开目录 C:\Qt\Qt5.7.0\5.7\Src ,就可以看到源码了。




如 QDialog 源码位置:




12、提升的窗口部件


1)用 Qt Creator 新建一个自定义Widget,如类名自定义为 “ModeSwitcherWidget ”

2)在 Qt Creator 自带的设计师界面中,右键,选择菜单 “提升为...”或“提升的窗口部件”,弹出“提升的窗口部件”界面,在此界面可设置自定义的 Widget 为提升的窗口部件。


       


3)在 Qt Creator 自带的设计师界面中,选中要提升的普通 Widget ,右键,选择菜单 “提升为” → “自定义的控件




4)如果想取消该控件的提升,右键,选择菜单 “取消 QWidget 的提升”即可





13、 Qt 运行文件的依赖库


1 > windows 系统下Qt 运行文件的依赖库寻找

系统:Windows 7

Qt构建套件:qt-opensource-windows-x86-mingw530-5.7.0.exe

Qt Creator版本:4.0.2

构建版本:release


A. 一般的应用程序,下面的dll就够了。其中platforms文件夹中是跟平台有关,这里只在windows平台运行,则这个文件夹下放 qwindows.dll就够了




B. QtWidgets ApplicationQtCreator自带的windeployqt 工具



新建一个文件夹“test”,将release版本的可执行文件“xxx.exe”放到“test”文件夹中,然后单击“开始菜单”—> “所有程序”—>“Qt 5.7.0” —>“Qt5.7”—>“MinGW 5.3.0 (32-bit)”—>“Qt 5.7 for Desktop (MinGW 5.3.0 32bit)”;






在命令窗口输入可执行文件xxx.exe路径,然后继续输入“windeployqt xxx.exe,回车。即可将所有需要的dll动态库文件拷贝到test文件夹中。






C. Qt Quick Application + QtCreator自带的windeployqt 工具


同上(B),只是将使用 windeployqt 工具命令更改为:


windeployqt xxx.exe --qmldir C:\Qt\Qt5.7.0\5.7\mingw53_32\qml

注意:使用 windeployqt工具拷贝的动态库,有时候并不需要那么多动态库,这时候就可以手动删除一些;有时候拷贝的并不全面,即还是有缺失的,这就需要手动去Qt安装路径拷贝,比如 粒子系统、qtcharts图表、webengine等,还有自定义的库或第三方库,也是需要手动拷贝的。







2 > Ubuntu 系统下Qt 运行文件的依赖库寻找

系统:Ubuntu 14.04.5

Qt构建套件:qt-opensource-linux-x86-5.5.1.run

Qt Creator版本:3.5.1

构建版本:release


Ubuntu下,寻找一个可执行文件运行时所依赖的库文件使用的是 ldd命令。

ldd命令 的作用是打印可执行文件依赖的共享库文件,它是 glibc 的一部分。


root@ubuntu:~# ldd --help
Usage: ldd [OPTION]... FILE...
      --help              print this help and exit
      --version           print version information and exit
  -d, --data-relocs       process data relocations
  -r, --function-relocs   process data and function relocations
  -u, --unused            print unused direct dependencies
  -v, --verbose           print all information

For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/eglibc/+bugs>.
root@ubuntu:~# 


ldd本身不是一个程序,而仅是一个shell脚本


root@ubuntu:~# which ldd
/usr/bin/ldd
root@ubuntu:~# ls -al /usr/bin/ldd
-rwxr-xr-x 1 root root 5424 May 26  2016 /usr/bin/ldd
root@ubuntu:~#  file  /usr/bin/ldd
/usr/bin/ldd: Bourne-Again shell script, ASCII text executable
root@ubuntu:~# 

在终端输入“ldd + 运行程序”,按下“Enter”,便可查看运行程序的依赖库情况




注意:使用 ldd 命令查看依赖动态库也可能不全面,这就需要去QT的安装目录下手动拷贝(/opt/Qt5.5.1/5.5/gcc/lib,或/opt/Qt5.5.1/5.5/gcc/plugins),其中/opt/Qt5.5.1/5.5/gcc/lib文件一般是拷贝到/lib或者/usr/lib下,/opt/Qt5.5.1/5.5/gcc/plugins中文件与运行文件在同一级目录下,另外,还有自定义的库或第三方库,也是需要手动拷贝的。



14、Qt 动态库路径查找(Ubuntu


在工程中使用 LIBS+=-Lxx LIBS+=-lxx可以指定动态库和静态库链接文件和路径,但是在运行程序时,对动态库的可能查找不到。

可以使用ldd 命令进行测试验证,是否所有的动态库都已经定位成功,查看方法请看13

动态库路径查找方法优先级如下,:

1 > 编译目标代码时指定的动态库搜索路径; QMAKE_RPATHDIR+=xxx 例如QMAKE_RPATHDIR+=/usr/local/lib ,连接时将使用 -rpath,/usr/local/lib/ 

2 > 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径;

3 > DT_RUNPATH 指定的动态库搜索路径(-Wl,--enable-new-dtags);

4 > 配置文档 /etc/ld.so.conf中指定的动态库搜索路径;

添加lib库路径方法如下:

/etc/ld.so.conf.d加入文件xxx.conf,写入

/usr/lib/qt

同样,执行下列命令使其立即生效

sudo ldconfig

5 > 默认的动态库搜索路径 /lib 

6> 默认的动态库搜索路径 /usr/lib 。


在上述1、2、4指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索的。


15、QWidget 关闭时触发的事件


触发关闭事件实际上就是重写 closeEvent() 事件。

当使用者想要关闭窗口的时候,closeEvent()事件被发送给窗口。

    //在头文件中加入
    protected:
        void closeEvent(QCloseEvent*event);

然后,在cpp完成closeEvent事件的处理

void DeviceDiscoverToolsPlugin::closeEvent(QCloseEvent *event) //此函数在QWidget关闭时执行
{

    QWidget::closeEvent(event);

}







 


会持续更新...





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值