• 10488阅读
  • 4回复

分享自己一些对qt的理解(原创) [复制链接]

上一主题 下一主题
离线浪漫天使
 
只看楼主 倒序阅读 楼主  发表于: 2006-06-09
一些关于qt3和qt4的理解

如果你用过了qt3,也用过qt4的话,肯定觉得变化很大,不是吗?
qt4没有了pro文件的管理
Removed project manager. Qt Designer now only reads and edits .ui files. It has no notion of a project (.pro file)
Qt4改变了.ui的文件格式,虽然提供了转化工具,大家还是觉得不好玩。
Changed format of .ui files. Qt Designer 4 cannot read files created by Qt Designer 3 and vice versa. However, we provide the tool uic3 to generate Qt 4 code out of Qt 3 .ui files, and to convert old .ui files into a format readable by Qt Designer 4.
更抠门的是,居然连c++的编辑器也不给我们用。
Removed code editor. Qt Designer can no longer be used to edit source files.
更深入一层来说,看一些qt4提供的例子,怎么觉得有点不大像qt3 c++的习惯,c++是可以这样的吗?qt4中自己的槽在哪里添加啊?

同样我们也会对qt3以前的.ui.h这个文件感到有点纳闷,看上去是头文件,但是进去看怎么看都觉得像是观念中的源文件,因为毕竟里面是实现特殊函数――槽(SLOT)功能的地方。

更烦的是,Qt3中用designer设计好了的.pro文件,然后用vc工具打开,添加一些自己改动,等到下次由于编译需要clean一下,再次用工具打开pro文件,天哪,我辛辛苦苦添加的东西到哪里去了啊?!!

本文试着根据自身的一些实践,结合论坛中的一些网友遇到的问题,说说自己的看法,希望能抛砖引玉,对大家学习qt有所帮助。

按照历史顺序,首先说qt3。

在qt3或者以前的版本中,可能大家的习惯做法是,打开designer,添加pro文件,设置头文件路径,设置是app还是lib,设置要连接lib的路径和对应的lib的名称;接着开始新建一个dialog,在上面添加按钮,然后保存成.ui文件;开始写main函数,像我这么懒的人,main函数都是根据designer生成的。一切都顺利的话,你可以选择开始qmake了,接着make(或者nmake等等);如果在WINDOWS下,也可以选择用vc中的qt工具栏打开pro文件,编译链接,一般情况下,你都会很高兴的看到自己第一个qt的界面。

对了,要添加自己的槽呢?
你可以在(Object)下面的Member选项卡里面找到Slot一项,添加一个槽,如果你在某个slot点击Edit的话,qt就会弹出一个窗口,这个窗口上面提到的.ui.h的文件所在。如果想初始化自己定义的一些变量,可以在function里面添加init()函数,当添加完以后,你会发现后面会多了(Constructor)这个东西,其实在.ui.h前面那段注释的代码里面就说得很清楚了,
/****************************************************************************
** ui.h extension file, included from the uic-generated form implementation.
**
** If you want to add, delete, or rename functions or slots, use
** Qt Designer to update this file, preserving your code.
**
** You should not define a constructor or destructor in this file.
** Instead, write your code in functions called init() and destroy().
** These will automatically be called by the form's constructor and
** destructor.
*****************************************************************************/

也可以通过打开根据ui生成的Form1.cpp看到,类的构造函数的最后面调用了init()这个函数,这个函数在没有添加的时候是没有出现在ui生成的Form1.cpp文件里面的。init()对应的就是destory()了,这个就不多说了。

不喜欢Form1这个类的名字,要改变类的名字怎么办?可以在ui上面点击右键选择Form setting ,在弹出的对话框里面会看到class name的一项,在那里写上自己喜欢的类名吧。这个类名就是相当于Form1,Form1怎么用,这个类就怎么用。

大家是不是觉得这些步骤很像vc的做法呢?具体点就是MFC的做法呢?

也有一些网友会根据qt文档里面的说法去做:写好了.h文件和.cpp文件,接着用
qmake –project
这样的方法来生成pro文件,个人觉得这样的做法不提倡,为什么呢?因为一般来说一个工程都要包含其他目录下的头文件,需要链接别的不是qt的库,这样的话就要对每次生成的pro文件进行添加修改,不是很方便。其次,有人喜欢把头文件和源文件分别放在不同的目录下,这样的话管理很方便,但是
qmake –project
只对当前目录下的头文件和源文件起作用。
至少在windows下,用
qmake –project
生成pro文件的话,后面的生成的.obj文件就很乱的
最好还是在designer里面的pro设置里面做这些吧。

论坛里面的有些牛人自己写pro文件的,这个就不是本人能够到达的境界了,没有能力在这里讨论了。

不管怎样,不就是为了得到Makefile吗?下面就专门看它怎么发飙了?
插播一下,真的要谢谢qmake,它那么容易就让我们得到了Makefile,Makefile是什么?!后面的一切都是听他指挥的,要是我们自己写的话,像我怎么懒的人才不写呢!!况且我也不大会写呢~_~

随便用一个文本编辑器打开Makefile,大概会看到下面的一些东西吧qt332版本的

#############################################################################
# Makefile for building: myqt332test
# Generated by qmake (1.07a) (Qt 3.3.2) on: Thu Jun 08 22:41:07 2006
# Project: myqt332test.pro
# Template: app
# Command: $(QMAKE) -o Makefile myqt332test.pro
#############################################################################

####### Compiler, tools and options

CC        =    cl
CXX        =    cl
LEX        = flex
YACC        = byacc
CFLAGS    =    -nologo -Zm200 -W3 -MDd -Zi -Gm -DUNICODE -DWIN32 -DQT_DLL -DQT_THREAD_SUPPORT
CXXFLAGS    =    -nologo -Zm200 -W3 -w34100 -w34189 -MDd -Zi -Gm -DUNICODE -DWIN32 -DQT_DLL -DQT_THREAD_SUPPORT
LEXFLAGS    =
YACCFLAGS    =-d
INCPATH    =     -I"$(QTDIR)\include" -I"D:\qttest\myqt332test" -I"D:\QT332\mkspecs\win32-msvc.net"
LINK    =    link
LFLAGS    =    /NOLOGO /DEBUG /SUBSYSTEM:WINDOWS /LIBPATH:"$(QTDIR)\lib"
LIBS    =     "qt-mt332.lib" "qtmain.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "imm32.lib" "winmm.lib" "wsock32.lib" "winspool.lib" "delayimp.lib" "opengl32.lib" "glu32.lib"
MOC        =    $(QTDIR)\bin\moc.exe
UIC        =    $(QTDIR)\bin\uic.exe
QMAKE        =    qmake
IDC        =    $(QTDIR)\bin\idc.exe
IDL        =    midl
ZIP        =    zip -r -9
COPY_FILE    =     copy
COPY_DIR    =     copy
DEL_FILE    =     del
DEL_DIR    =     rmdir
MOVE        =     move
CHK_DIR_EXISTS =    if not exist
MKDIR        =    mkdir
INSTALL_FILE= $(COPY_FILE)
INSTALL_DIR = $(COPY_DIR)

####### Files

HEADERS =    
SOURCES =    main.cpp
OBJECTS =    main.obj \
       myqt332test.obj
FORMS =    myqt332test.ui
UICDECLS =    myqt332test.h
UICIMPLS =    myqt332test.cpp
SRCMOC    =    moc_myqt332test.cpp
OBJMOC    =    moc_myqt332test.obj
DIST    =    
TARGET    =    myqt332test.exe

####### Implicit rules

.SUFFIXES: .c .cpp .cc .cxx .C

{.}.cpp{}.obj::
   $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<<
   $<
<<

{.}.cc{}.obj::
   $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<<
   $<
<<

{.}.cxx{}.obj::
   $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<<
   $<
<<

{.}.C{}.obj::
   $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<<
   $<
<<

{.}.c{}.obj::
   $(CC) -c $(CFLAGS) $(INCPATH) -Fo @<<
   $<
<<

####### Build rules

all: Makefile $(TARGET)

$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC)
   $(LINK) $(LFLAGS) /OUT:$(TARGET) @<<
    $(OBJECTS) $(OBJMOC) $(LIBS)
<<


mocables: $(SRCMOC)
uicables: $(UICIMPLS) $(UICDECLS)

Makefile: myqt332test.pro D:\QT332\mkspecs\win32-msvc.net\qmake.conf ..\..\QT332\lib\qtmain.prl
   $(QMAKE) -o Makefile myqt332test.pro
qmake:
   @$(QMAKE) -o Makefile myqt332test.pro

dist:
   $(ZIP) myqt332test.zip $(SOURCES) $(HEADERS) $(DIST) $(FORMS) D:/qttest/myqt332test/myqt332test.pro ..\..\QT332\lib\qtmain.prl myqt332test.ui.h

uiclean:
   -$(DEL_FILE) myqt332test.h
   -$(DEL_FILE) myqt332test.cpp
mocclean:
   -$(DEL_FILE) moc_myqt332test.cpp
   -$(DEL_FILE) moc_myqt332test.obj
clean: uiclean mocclean
   -$(DEL_FILE) main.obj
   -$(DEL_FILE) myqt332test.obj
   -$(DEL_FILE) myqt332test.pdb
   -$(DEL_FILE) myqt332test.ilk
   -$(DEL_FILE) vc*.pdb
   -$(DEL_FILE) vc*.idb




FORCE:

distclean: clean
   -$(DEL_FILE) $(TARGET)

####### Compile

main.obj: main.cpp \
       myqt332test.h \
       

myqt332test.h: myqt332test.ui
   $(UIC) myqt332test.ui -o myqt332test.h

myqt332test.cpp: myqt332test.h myqt332test.ui
   $(UIC) myqt332test.ui -i myqt332test.h -o myqt332test.cpp

myqt332test.obj: myqt332test.cpp \
       myqt332test.ui.h \
       myqt332test.h \
       

moc_myqt332test.obj: moc_myqt332test.cpp myqt332test.h

moc_myqt332test.cpp: $(MOC) myqt332test.h
   $(MOC) myqt332test.h -o moc_myqt332test.cpp

####### Install

install:

uninstall:



在里面,我们可以看到,myqt332test.h和myqt332test.cpp p是怎么生成,moc_*.cpp是怎么生成的,使用的是那个c++的编译器,clean的话会清除什么东西

有点晕了吧,坚持一下,你会有收获的,关键来看看这里

myqt332test.h: myqt332test.ui
   $(UIC) myqt332test.ui -o myqt332test.h

myqt332test.cpp: myqt332test.h myqt332test.ui
   $(UIC) myqt332test.ui -i myqt332test.h -o myqt332test.cpp

myqt332test.obj: myqt332test.cpp \
       myqt332test.ui.h \
       myqt332test.h \
       

moc_myqt332test.obj: moc_myqt332test.cpp myqt332test.h

moc_myqt332test.cpp: $(MOC) myqt332test.h
   $(MOC) myqt332test.h -o moc_myqt332test.cpp

myqt332test.h 是靠这句话生成的 $(UIC) myqt332test.ui -o myqt332test.h
myqt332test.cpp 是靠这句话生成的 $(UIC) myqt332test.ui -i myqt332test.h -o myqt332test.cpp
moc_myqt332test.cpp 是靠这句话生成的 $(MOC) myqt332test.h -o moc_myqt332test.cpp

至于$(UIC) 和 $(MOC)是什么意思,?
MOC        =    $(QTDIR)\bin\moc.exe
UIC        =    $(QTDIR)\bin\uic.exe
QMAKE        =    qmake

一切的一切,都在Makefile里面说得清清楚楚。
这也是经常提到的为什么我的一些修改会丢了呢?因为你的修改是在myqt332test.h和myqt332test.cpp里面的,clean以后 再次qmake会重新生成的。所以你要改什么控件的话,最好还是在designer里面修改,但是myqt332test.ui.h不一样,它不是生成的,不会被覆盖。其实myqt332test.ui.h里面是一些自己定义的东西,比如槽,比如变量的初始化,所以qt3的设计者就是要我们在myqt332test.ui.h里面写东西,在init()里面初始化,而不是像平时的c++一样,在myqt332test.h里面定义变量,跑到myqt332test.cpp里面写东西,这个在qt4里面改变了方式了,呵呵,不觉得myqt332test.ui.h有点怪怪的吗?

在生成的myqt332test.cpp 里面可以看到,里面的控件是怎么创建的。

myqt332test::myqt332test( QWidget* parent, const char* name, bool modal, WFlags fl )
  : QDialog( parent, name, modal, fl )
{
  if ( !name )
   setName( "myqt332test" );

  pushButton1 = new QPushButton( this, "pushButton1" );
  pushButton1->setGeometry( QRect( 110, 115, 126, 26 ) );

  pushButton2 = new QPushButton( this, "pushButton2" );
  pushButton2->setGeometry( QRect( 110, 210, 131, 31 ) );

  textLabel1 = new QLabel( this, "textLabel1" );
  textLabel1->setGeometry( QRect( 370, 180, 81, 46 ) );
  languageChange();
  resize( QSize(600, 480).expandedTo(minimumSizeHint()) );
  clearWState( WState_Polished );
  init();
}
看到了吧,里面控件的父类都是this,在这里可能你觉得的很自然,到了qt4就不一样了,到qt4的时候再详细讨论。


看完了makefile ,再来看看qt3的designer的一些特色。
其实个人觉得qt4以前的designer很像vc,比如lib和include 的路径的设置,生成dll还是exe,新建一个槽或者函数,变量的添加,关键字的着色,都可以在designer里面做到,就差不能编译和调试,这也是很多人感到不爽的地方,qt4干脆就把这些砍掉,狠^_^

不过layout这个东西确实让人耳目一新,还有就是那个弹簧 ,
qt3大概就先说这些吧,以后想到什么再补吧,

下面把目光放在qt4身上。对于designer来说,她确实苗条一些了。
首先是生成的头文件的默认的名字由qt3的classname.h变成了ui_*.h,其次就是创建控件的方式有了很大不同,这或许是很多网友感到郁闷的地方,还有就是pro文件不再跟designer在一起了。更要命的是,很多控件类的名字都改变了。但是有一点值得肯定的是:事物总是朝着好的方向发展的。
随便在designer里面画几个控件。保存.ui文件。然后写一个main函数
大概是这个样子吧

#include <qapplication.h>
#include "ui_mytest.h"

int main(int argc, char *argv[])
{
  QApplication app(argc,argv);

  QWidget *dlg = new QWidget();
  Ui::mytest ui;
  ui.setupUi(dlg);
 
  dlg->show();

  return app.exec();
}

大家可能对这段身材比较感兴趣
  QWidget *dlg = new QWidget();
  Ui::mytest ui;
  ui.setupUi(dlg);
 
dlg->show();

为什么show的是dlg呢?setupUi到底做了什么?为什么要Ui::mytest ui这样定义呢?
看头看尾,看来只好在ui_mytest.h里面找答案了;

#ifndef UI_MYTEST_H
#define UI_MYTEST_H

#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QWidget>

class Ui_mytest
{
public:
  QPushButton *pushButton;
  QLabel *label;
  QPushButton *pushButton_2;

  void setupUi(QWidget *mytest)
  {
  mytest->setObjectName(QString::fromUtf8("mytest"));
  mytest->resize(QSize(400, 300).expandedTo(mytest->minimumSizeHint()));
  pushButton = new QPushButton(mytest);
  pushButton->setObjectName(QString::fromUtf8("pushButton"));
  pushButton->setGeometry(QRect(70, 100, 75, 23));
  label = new QLabel(mytest);
  label->setObjectName(QString::fromUtf8("label"));
  label->setGeometry(QRect(183, 110, 111, 31));
  pushButton_2 = new QPushButton(mytest);
  pushButton_2->setObjectName(QString::fromUtf8("pushButton_2"));
  pushButton_2->setGeometry(QRect(80, 200, 75, 23));
  retranslateUi(mytest);

  QMetaObject::connectSlotsByName(mytest);
  } // setupUi

  void retranslateUi(QWidget *mytest)
  {
  mytest->setWindowTitle(QApplication::translate("mytest", "Form", 0, QApplication::UnicodeUTF8));
  pushButton->setText(QApplication::translate("mytest", "PushButton", 0, QApplication::UnicodeUTF8));
  label->setText(QApplication::translate("mytest", "TextLabel", 0, QApplication::UnicodeUTF8));
  pushButton_2->setText(QApplication::translate("mytest", "PushButton", 0, QApplication::UnicodeUTF8));
  Q_UNUSED(mytest);
  } // retranslateUi

};

namespace Ui {
  class mytest: public Ui_mytest {};
} // namespace Ui

#endif // UI_MYTEST_H

看来答案已经差不多了。
main.cpp 里面的这句话其实创建一个“画板”,好让你在上面画东西;
QWidget *dlg = new QWidget();
Ui::mytest ui;
这句话的是定义名字空间namespace Ui 里面的一个类成员class mytest的一个对象 ui;
要看到这个class mytest 是共有继承这个类的public Ui_mytest,而这个类class Ui_mytest却不是继承任何qt的类。所以setupUi()要用把画板的指针传进来,
ui.setupUi(dlg);
然后所有的控件的创建都是在这个画板上面进行的。
最后我们show的时候就把dlg show出去。其实这个时候上面已经有我们画的东西(控件)了。
给你一张白纸(dlg),画好你的东西,然后帖到画板上(setupUi),show的时候当然就是你画的东西啦!
注意一个小细节,名字空间里面的类的名字怎么设置的?是在designer画ui的时候,右键菜单里面有个change objName,这里就是你改变
namespace Ui {
  class mytest: public Ui_mytest {};
}
中的 class mytest的时候。

休息一下!!
对了,那些qt关键的槽在那里设置啊?这可是qt的卖点啊?

那是因为我们给的画板太白了!它只是简单的一个widget,没有我们自己的槽,还是自己动手吧!
因为我们自己的槽人家qt怎么知道是什么啊?
mytest.h

#include "ui_mytest.h"
#include <qwidget.h>


class mytest : public QWidget
{
   Q_OBJECT//这个对于slots来说很重要,不要忘记了
public:

  mytest();
  virtual ~mytest();


public slots:
  void myslots();


private :
  Ui::mytest ui;

};

各位看官注意了!这个class mytest 和 Ui::mytest 是不一样的,这里就体现了qt4 中designer的特点,她只是画Ui而已,其他的回归c++
mytest.cpp

#include "mytest.h"
#include <qmessagebox.h>

mytest::mytest()
{
  ui.setupUi(this);//以后写构造函数第一件事就是写这个函数
  connect(ui.pushButton,SIGNAL(clicked()),this,SLOT(myslots()));
}

mytest::~mytest()
{
 
}

void mytest::myslots()
{
  QMessageBox::information(this,"debug","myslots");
}

这里要注意的是connect(ui.pushButton,SIGNAL(clicked()),this,SLOT(myslots()));
中的ui.pushButton,而不是经常写的pushButton,这也是由于是在pushButton Ui里面的
,而不是在class mytest里面的。
对应的main.cpp就变成了这个样子了。

#include <qapplication.h>
//#include "ui_mytest.h"

#include "mytest.h"

int main(int argc, char *argv[])
{
  QApplication app(argc,argv);

//   QWidget *dlg = new QWidget();
//   Ui::mytest ui;
//   ui.setupUi(dlg);
 
//   dlg->show();


   mytest *dlg = new mytest();
   dlg->show();    

  return app.exec();
}

一句话,到处都体现了qt4的设计思想,designer 只是画控件的工具。
很久没有写东西了,语句不是很通顺,也是第一次写这样的东西,难免有错漏,请各位网友指正,共同进步。


终于在世界杯开幕前赶出来了!!
描述:qt332.windowsxp,.net下通过
附件: myqt332test.rar (303 K) 下载次数:22
描述:qt4.1.0开源版,windows2000,vc6.0通过(没有自己的slots)
附件: mytest.rar (19 K) 下载次数:15
描述:qt4.1.0开源版,windows2000,vc6.0通过(有自己的slots)
附件: mytest2.rar (27 K) 下载次数:23
离线tuizi7835

只看该作者 1楼 发表于: 2006-06-16
牛,支持一下!
离线cavendish

只看该作者 2楼 发表于: 2006-06-16
手写pro文件不算麻烦吧
如果是从qt 2.x开始写代码
或者不是习惯于IDE的开发人员
写个pro文件实在太简单了

毕竟还没让你写makefile

少于100人的qt团队现在是专心做好自己的工作
IDE实在不是一个小东西
离线weihua
只看该作者 3楼 发表于: 2006-06-19
我用得是QT4.1.3,怎么没找到 pro设置 , 请问它在哪,谢谢!

引用第0楼浪漫天使2006-06-09 16:53发表的“分享自己一些对qt的理解(原创)”:
最好还是在designer里面的pro设置里面做这些吧。
离线浪漫天使
只看该作者 4楼 发表于: 2006-06-19
引用第3楼weihua2006-06-19 15:45发表的“”:
我用得是QT4.1.3,怎么没找到 pro设置 , 请问它在哪,谢谢!

按照历史顺序,首先说qt3 ,我说的是在qt3里面的

呵呵,qt4我也没有看到,可以用qmake -project生成,也可以自己写pro,感觉自己写的话,好自由啊
快速回复
限100 字节
 
上一个 下一个