Category Archives: Qt

about Qtcn

Qtcn目前好象还差的比较远,缺少真正懂qt的人,可笑的这两天还在讨论c++里的class和struct,居然有这么多人搞不清楚,还固执的可笑。

F.
Wu给我写信说,qtcn他看了一下,暂时不想去,还没有形成讨论问题的氛围,有的只是几个可笑的连c/c++还搞不清楚的人在讨论幼稚的问题。将我也骂
进里面去了,我居然还在struct和class里发了好几个帖子,想使他们搞明白是怎么回事,结果被人胡搞蛮缠,成了谩骂的帖子了。只是我从来没在一个
技术论坛上会看到这种情况,不仔细研究别人给的答案,单凭自己的可怜的一点知识来判定回帖人的对错,这种后果是很可怕的,这样的风气也不可取,从个人讲妨碍个人的进步,从论坛上这种习惯会传染的。好在终于决定不再看这种帖子了。

c/c++应该是Qt的基础,c/c++没学好,学习Qt会有较大的问题。

重载最小化的默认behavior

花了整整一天的时间!真是很不容易。首先,在event()里判定 type()==QEvent::WindowStateChange是不行的,(1)WindowStateChange在最小化完成后调用,(2) hide()在event()里调用,没有预期效果,表现在hide后居然还有icon在任务栏上。其次,在WindowStateChange前,会调 用hideEvent(),但重载hideEvent仍然不成,hide后在任务栏上仍有icon。
谢谢qtforum的bubu提示,他给出的方案是:
bool testMinimize::winEvent(MSG *message, long *result)
{
if (message->message == WM_SYSCOMMAND && message->wParam == SC_MINIMIZE) {
ShowWindow(winId(), SW_HIDE); //WinAPI
(*result) = false;
d->tray->show();
return true;
}

}
然后调用 ShowWindow(winId(), SW_SHOW);显示
但有一个不足,上述hide后,不能用QMainWindow::show()回来。我在bubu的基础上改了一下,如下:
bool testMinimize::winEvent(MSG *message, long *result)
{
if (message->message == WM_SYSCOMMAND && message->wParam == SC_MINIMIZE) {
// ShowWindow(winId(), SW_HIDE); //WinAPI
hide();
(*result) = false;
d->tray->show();
return true;
}
return QMainWindow::winEvent(message, result);
}
居然发现hide在winEvent里可以用。惊喜!这样就可以用QMainWindow::show()回来了。
感谢bubu at qtforum!

使得QDialog关闭的时候不自动退出

使得QDialog关闭的时候不自动退出
giscn[at]msn[dot]com

适用情况:当主窗口hide在后台,这时在trayIcon上打开一个about窗口,关闭此about
窗口,将自动退出整个程序。
原因:Qt 4.0.1自动将lastWindowClosed与quit()相连。而这时主窗口被隐藏,在关闭
about窗口时,因为检测到about窗口有WA_QuitOnClose属性,在about关闭后,继续检
测有无visible的带WA_QuitOnClose属性的窗口(lastWindowClosed),因为检测到没
有,所以激发quit(),从而退出。
solution: 在about dialog的合适位置(一般是constructor)加入
setAttribute(Qt::WA_QuitOnClose, false); 清除WA_QuitOnClose标志。这样在关闭
about时,不会继续检测lastWindowClosed,从而不激发quit。

得到russian一个朋友给的qt 4.01 patch

1. 下载qt-win-eval-4.0.1,自己到trolltech下载
2. 下载patch
3. 安装qt eval
4. 将patch的内容解压缩到bin目录下
5. ok

声明,本人使用opensource版,且准备要购买Qt 4.x,本信息只是在网上看着了,转帖一下,而patch是russia的朋友在rapidshare发现的,然后转告于我。如有不妥,请告知,即刻删除。

Qt 4.0.1 signal的模板参数问题

描述如下:singal带2个参数,第一个是模板类型的参数,第二个是一个类,在4.01下
面编译通不过,即便第二个参数是int这样的简单类型,也不行。但如果只有一个参数
(即模板参数),可以正常通过。Qt 4.0.0没有这个问题。
解决方案:通过typedef将模板参数定义成一个别名。编译通过。

Qt里的属性(property)

Qt里的属性(property)
giscn[at]msn[dot]com


1.属性有什么用?
由于c++类具备封装特性,不推荐对类成员变量(class
variables)进行直接存取。现代编译器引用属性(property)的概念,对成员变量进行安全的存取。比如在win平台下
vc7有类似于__property或[property]的支持。Qt由于要实现其跨平台(cross
platform),引入一套独特的属性系统。其底层是由meta compiling进行支持。

2.格式
    Q_PROPERTY(type name
               READ getFunction
               [WRITE setFunction]
               [RESET resetFunction]
               [DESIGNABLE bool]
               [SCRIPTABLE bool]
               [STORED bool])

  • Q_PROPERTY: qt里定义的宏;
  • type name: 即类型名+属性名,属性名(name)在QObject的setProperty里被引用;
  • READ: 设置读取成员变量的函数名,一定要是const,可以返回void,Qvariant支持的对象,指针,或const的引用。READ是必须的,而write, reset等则是可选的;只有READ的属性为只读属性;
  • WRITE: 写成员变量的函数名,返回值必须是void,可以设置一个参数,这个参数可以是void,QVaraint支持的变量,指针,或const的引用。可选;具备READ和WRITe的属性是可读写属性。
  • DESIGNABLE: 指示该属性是否被图形编辑器(比如designer)使用。默认是TRUE;
  • SCRIPTABLE: 指示是否在script里使用,Trolltech公司同时有基于Qt的QSA,用于在应用程序的脚本编程;默认是TRUE;
  • STORED: 指示是否可被持久化(persistence)。只有WRITE被设定的时候,STORED才有效。默认是TRUE。

3. 使用
比有一个类,

class MyClass : public QObject
{
Q_OBJECT

public:
  MyClass (QString f) {this->f =f;}
  ~MyClass() {}

//property begin
  QString getF() const {return f;}
  void setF(QString ff) {f=ff;} 
//property end

private:
  QString f;
};

这时在public之前定义property
Q_PROPERTY (QString F READ getF WRITE setF)

照惯例,读取函数往往省略get,即定义了
QString F() const {return f;}
这时,Q_PROPERTY (QString F READ F WRITE setF)
但实际上,读取、写、和重置(reset)函数可以是任何名字,比如前面用getF。

在使用时,属性跟一般的成员函数一样被使用,比如:
MyClass classA("initial");
QString out=classA.getF();
//out = "initial"
QString t="this is a test";
classA.setF(t);
//classA里的f现在是"this is a test"

此外,可以通过QObject::setProperty()和property()来使用属性,比如
MyClass classB("classB");
//这时的f是"classB"
classB.setProperty("F", "this is a test");
//这时调用setF("this is a test"),成员变量f现在是"this is a test"

使用setProperty可能效率比直接调用setF低,但注意到setProperty是基类的成员,所以通过QObject::property/setProperty可以遍历全部派生自QOjbect的类的属性。比如:
QObject* p = &classA;
p->setProperty("F", "test A");
p=&classB;
p->setProperty("F", "test B");
熟悉多态的朋友,马上就应该联想到这种机制的一些优越性。其中奥秘请看多类的相关描述,这里主要讲Qt的属性,不赘。

QObject::property/setProperty跟QMetaObject::propertyCount(),和QMetaObject::property()结合起来,可以实现动态的函数调用,类似于dotnet里的reflection机制。

4. 如果property的参数是enum,那么在定义Q_PROPERTY时,必须先告诉meta system使用的enum,使用宏Q_ENUMS,次序无关,如:

Q_PROPERTY(Priority priority READ priority WRITE setPriority)
Q_ENUMS(Priority)

其中Priority是枚举类型。

5.一个较为复杂的例子,使用了一个引用输入属性的写函数。请注意,此引用必须为const。

////CaliforniaWhiteWine.h
#include <QObject>

class WhiteWine
{};

class CaliforniaWhiteWine :
    public QObject
{
    Q_OBJECT
    Q_PROPERTY(WhiteWine& m_wine READ getWine WRITE setWine)
public:
    CaliforniaWhiteWine();
    CaliforniaWhiteWine(WhiteWine& wine);
    ~CaliforniaWhiteWine();

    WhiteWine& getWine() const;
    void setWine(const WhiteWine& wine)
    {
        delete m_wine;
        *m_wine = wine;
    }
protected:
    WhiteWine* m_wine;
};

////CaliforniaWhiteWine.cpp
#include ".californiawhitewine.h"

CaliforniaWhiteWine::CaliforniaWhiteWine(void)
{
    this->m_wine=new WhiteWine();
}

CaliforniaWhiteWine::~CaliforniaWhiteWine(void)
{
    delete m_wine;
}

CaliforniaWhiteWine::CaliforniaWhiteWine(WhiteWine& wine)
{
   
}

WhiteWine& CaliforniaWhiteWine::getWine() const
{
    return *m_wine;
}

qtcn.org

才发现一个新的中文Qt讨论站(www.qtcn.org)。站长有志于将Qt
4的文档翻译成中文。很好很有意义的工作,但工作量怕不小,是个漫长的过程。但Trolltech作为一个商业公司,如果她感觉有必要做成中文文档来吸引
中国的开发者的话,估计他们自己会做这事情,开源社区却不宜花太多时间在文档的翻译工作上面。只是国内的Qt coder不多,而且水平基本偏低。
也许多写一些中文的入门引导性的文章(即便是英文的,同样有意义),在目前来看,我感觉居于比较重要的位置。
技术论坛还是要写位在技术讨论上,不管是qtcn还是cngis。只是坚持下去不是件容易的事。
最近在study win32  api class -> Qt
class的转化,TT编程人员真是做了件了不起的工作。比如meta
compiling和Qt的wrapping都是值得写c++代码的人借鉴的技术。看到wxWidget讲,Qt的这种meta
compile导致Qt不是一种真正的纯c++。并不十分赞同。在meta
compile底层讲,预编译的效果是纯cpp,从较上层讲,能最大限度简化编程人员的工作量就是成功。
不过象wxWidget这样使用消息映射宏,也是不错的一种选择。估计是借鉴了mfc。没有太深钻研wxw,以后有时间再看。

一个Qt论坛

发现一个Qt相关的技术论坛,很好!
这是地址:http://prog.org.ru/forum/forum_14_293a41060711d9f8a71a60fe1e5e890e.html
另外,俄罗斯的盗版好象比中国的还要厉害,很多新软件,在google.ru上都能找着破解

一 个小 tip,特别是找软件破解的时候,不妨除了用google.com,也用用google.ru等区域性的搜索,也许会带给你惊喜;另外最新的软件一般都出 现在eDonkey上面,所以不要忘了到eDonkey上找找(这不是bt可以替代的,eDonkey上的资源很丰富,当然内容也是乱七八糟的,就看大家 如何对待了)。

revised lineEdit

目的:当第一次鼠标点到lineEdit的时候,自动将全部的text选上,而不是默认的将光标置于某个位置
解决方法:重载focusInEvent
难点:click时产生QFocusEvent和MousePressEvent,然后MousePressEvent的处理在focusInEvent之后,所以即便将focuseInEvent重载后,mouse event还是会将光标置到点击的位置,而不是选定全部。这时首先判断是否因为mouse focus造成的,如是的话,由重新发送一个由tab引发的focus in(默认的tab引起的focus是全部选定)。这样就ok了。
 
Purpose: when the first time of clicking the line edit widget, the whole text will be selected, other than the default action, which would insert the cursor in a certain position in the line edit.
Solution: override the focusInEvent virtual method.
Points to be specially addressed:  In a normal way, when the focus changed by the mouse clicking, the default action includes (1) invoking focusIn event which in turn calls the focusInEvent, and (2) normal mouse event which inserts the cursor into a proper position. This will bring a problem, whatever you set the focusInEvent event (for ex., call selectionAll to select all the text) , the normal mouse event will move the cursor to a certain position. A workaround is listing as following:  first check the reason causing the focus change, if it’s due to mouse click, then post in the event queue a tab focus event which by defaut will select all the text in a line edit widget.  
 
 
 
代码:
void PmFocusHandledLineEdit::focusInEvent( QFocusEvent * event )
{
  if (event->reason()==Qt::MouseFocusReason)
  {
    QFocusEvent *fe=new QFocusEvent(QEvent::FocusIn, Qt::TabFocusReason);
    QApplication::postEvent(this, fe);
  }
  else
  {
    QLineEdit::focusInEvent(event);
  }
}

Qt中的事件

Qt中的事件
giscn[at]msn[dot]com
 
1.事件的来源
来源于a)windows系统的事件,经Qt的包装(如QMouseEvent);b)Qt内置的事件(如
QTimerEvent);c)应用程序自定义的事件
 
2.处理事件的位置
2.1 重载虚拟方法
比如一个按钮,要自定义左键click时的行为,可以这样做:
a. 从一个QPushButton上派生一个子类如MyPushButton
b. 重载void MyPushButton::mousePressEvent(QMouseEvent *event)
* 一般来讲,除非要重新改写这个事件的默认行为,否则如果仅是为了扩展其功能,最好在
函数的最后call默认的父类处理方法,如QPushButton::mousePressEvent(event);
* 在调用mousePressEvent这些特定的事件前,先调用通用事件处理函数,QObject::event()
。因此,对于一些特殊情况,我们必须要重定义event(),如我们要对tab键进行重定义。默
认的tab键是将focus移到下一个widget上去。比如在一个text edit widget里,我们可能希
望tab键是向右形成一个置表位置,这时需要在text edit widget的event()进行处理。
2.2 event filter(事件过滤器)方法
一个对象的event filter的处理优先级在 该对象的 event()方法调用之前。这时,filter对
象的eventFilter()方法被调用
* 使用QCoreApplication的事件过滤,可以将任何事件在进行具体对象之前,进行处理。但
需要注意,这可能会使得整个事件处理过程变慢。
  • Reimplementing QCoreApplication::notify. This is very powerful, providing complete control; but only one subclass can be active at a time.
  • Installing an event filter on QCoreApplication::instance(). Such an event filter is able to process all events for all widgets, so it’s just as powerful as reimplementing notify(); furthermore, it’s possible to have more than one application-global event filter. Global event filters even see mouse events for disabled widgets.
  • Reimplementing QObject::event() (as QWidget does). If you do this you get Tab key presses, and you get to see the events before any widget-specific event filters.
  • Installing an event filter on the object. Such an event filter gets all the events except Tab and Shift-Tab key presses.
  • Reimplementing paintEvent(), mousePressEvent() and so on. This is the commonest, easiest and least powerful way.
3. 自定义事件
3.1 自定义事件从QEvent派出,该event number必须大于QEvent::User
3.2 使用postEvent和sendEvent方法派遣自定义事件
* postEvent实质是将事件推进事件循环(event loop),马上返回。事件的实际发送可能在稍
后的一个事件处理时钟内。
* 在某种意义上,程序可以直接调用对象的对应事件函数,而绕过postEvent。但存在不足,
a)很多事件处理函数是protected,意味着你不能直接调用;b)这种直接调用将绕过event
filter;Qt的解决方法是sendEvent。比如repaint()实质是调用了sendEvent。
* sendEvent等待事件被发送成功或失败后才返回。
* postEvent的一个好处是多个posted的event可以被压缩成单一的event,从而提高了效率。
* 可以使用QCoreApplication::sendPostedEvents强迫Qt马上进入事件循环(event loop)派
遣事件。
 
4. 事件的传播(propogation)
如果事件在目标对象上得不到处理,事件向上一层进行传播,直到最顶层的widget为止。
如果得到事件的对象,调用了accept(),则事件停止继续传播;如果调用了ignore(),事件向上一级继续传播。
Qt对自定义事件处理函数的默认返回值是accept(),但默认的事件处理函数是ingore()。因此,如果要继续向上传播,调用QWidget的默认处理函数即可。到时为止的话,不必显式调用accept()。
但在event处理函数里,返回true表示accept,返回false表示向上级传播。
* 在closeEvent是个特殊情形,accept表示quit,ignore表示取消,所以最好在closeEvent显式调用accept和ignore。
 
5. tips
5.1 使用event->type得到事件的具体类型,对之进行判断,是否是需要的类型(比如
KeyPress),然后进行相应处理
5.2 使用static_cast<specific event type *>对通用事件转换成特定类型,比如将event转
成QKeyEvent *,然后调用QKeyEvent::key()取得按下什么键。
5.3 使用sendEvent时,参数 event,必须是局部变量,因为sendEvent不负责对event的删除
。而postEvent的event参数,则必须是 new分配的heap对象,post完了后会自动删除。