顯示具有 Qt 標籤的文章。 顯示所有文章
顯示具有 Qt 標籤的文章。 顯示所有文章

2009-11-27

Qt Conference -Taiwan 2009

For those of you who don't know yet, a Qt Tech Conference will be held on December 16th 2009 in Taipei. The agenda should be as follows Time Topics
  • 9:30 Guest registration
  • 10:00 Key-note: Qt Strategy & Roadmap
  • 10:30 Product presentation: Qt 4.6 Technical highlights
  • 11:30 Embedded case-study
  • 12:00 Lunch & demos
  • 13:00 Embedded case-study
  • 13:30 Tech session: An Introduction to Qt development for Symbian
  • 14:15 Tea-break & demo
  • 14:30 Tech session: Introducing the Qt Kinetic Project and QML
  • 15:15 Tech session: Using Multi-touch and gesture with Qt
  • 16:00 Lucky-draw and Closing remarks

[Android] Create compound controls in Qt and Android

If you are a programmer who is familiar with Qt and is writing Android application at the same time, just like me. You might discover that creating a compound control widget in Android and Qt is a bit different. For example, I would like a compound control widget that shows current time and am/pm label if the user prefers not to use 24-hour format.

In Qt, you might extend a QWidget and attach a derived QLayout to it.

class CompondTimeWidget : public QWidget {
public:
    CompondTimeWidget(QWidget* parent) : QWidget(parent) {
        QHBoxLayout* mainLayout = new QHBoxLayout(this);
        // ...
    }
    // ...
};

The QWidget and QLayout are in the difference class hierarchy and every QWidget needs a layout engine attached to it to layout child widgets defined inside it.

But, in Android, things are a bit different. The View and LinearLayout, for instance, are in the same class inheritance hierarchy. For this task, it's better to be done like this,

public class CompoundTimeWidget extends LinearLayout {
    public CompoundTimeWidget(Context context, AttributeSet attrs) {
        super(context, attrs);

        //
        TextView label = new TextView(context);
        addView(label, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

        // Get the rest of the design from xml file.
        View amPmView = mLayoutInflater.inflate(R.layout.am_pm_widget, this, false);
        addView(amPmView);

        // ...
    }
    // ...
}

I am not very biased towards Qt. Still, it's not natural to say, a widget is a LinearLayout. Which one is better? You tell me.

2009-04-30

Use QSettings

Normally, different applications have different ways to handle user preferences. For instance, it may be natural to choose Tcl script to save preferences for those applications that support Tcl scripting. But some specific settings, like window geometries opened last time, we don't want to trouble users to modify manually. We can choose whatever we feel convenient and they don't care about these settings.

In this case, the best way to handle this is using QSettings. In Unix platforms, QSettings put setting files under ~/.config according to application name and the organization that produces it. You may see directory structure like this,

[yenliangl@halo]:~/.config > ll total 13 drwx------ 2 yenliangl staff 512 May 16 2007 autostart/ drwxr-x--- 2 yenliangl staff 512 Apr 7 19:30 fixit/ drwx------ 2 yenliangl staff 512 Apr 30 12:28 gtk-2.0/ drwxr-x--- 2 yenliangl staff 512 Jul 17 2008 menus/ drwxr-x--- 2 yenliangl staff 512 Dec 24 16:43 Synopsys/ drwxr-xr-x 2 yenliangl staff 512 Jul 10 2007 Trolltech/ -rw------- 1 yenliangl staff 5769 Apr 22 13:47 Trolltech.conf -rw-r----- 1 yenliangl staff 242 Apr 13 18:38 Unknown Organization.conf
All Qt-related settings are located at Trolltech/ or in Trolltech.conf. How do we use QSettings? First, we let QSettings know our organization and product by,
   QCoreApplication::setOrganizationName( "SomeCompany" );
 QCoreApplication::setOrganizationDomain( "somecompany.com" );
 QCoreApplication::setApplicationName( "MyTool" );
and then, we have two private methods defined in our MainWindow class to write/read settings,
class MainWindow : public QMainWindow {
Q_OBJECT
public:
void closeEvent(QCloseEvent* e);
// ...

private:
void read_settings();
void write_settings();
// ...
};
In MainWindow::MainWindow(), we add a call to read_settings(),
MainWindow::MainWindow( /* ... */ )
{
// ...
read_settings();
}
and add a call to write_settings() as we exit application,
void MainWindow::closeEvent(QCloseEvent* e)
{
 // ...
 write_settings();
}
The definitions of read_settings() and write_settings() should look like,
void MainWindow::read_settings()
{
  QSettings settings;
  settings.beginGroup( "MainWindow" );
  restoreState( settings.value( "wm_state" ).toByteArray() ); // 可能有問題喔,如下。
  resize( settings.value( "size", QSize( 400, 400 ) ).toSize() );
  move( settings.value( "pos" ).toPoint() );
  settings.endGroup();
}

void MainWindow::write_settings()
{
  QSettings settings;
  settings.beginGroup( "MainWindow" );
  settings.setValue( "wm_state", saveState() ); // 可能有問題喔,如下。
  settings.setValue( "size", size() );
  settings.setValue( "pos", pos() );
  settings.endGroup();
}
set? not yet. If you are using QDockWidget or QToolBar in your application, we should see an error message at application run-time, saying that QDockWidget doesn't have objectName property set. From release note of Qt4, you should find,
The QMainWindow::saveState() and QMainWindow::restoreState() functions no longer fallback to using the windowTitle property when the objectName property is not set on a QToolBar or QDockWidget; this behavior was undocumented and has been removed.
It points out that you need to set objectName property manually. Simple!
myDock->setObjectName("whatever name"); // Or/And
myToolBar->setObjectName("whatever name");
Now. We're done. Run your application. You will discover your application remembers the window state and even the states of dock widgets.

2009-04-29

Qt4的安裝與編譯

在下載及安裝之前,先試著了解自己的需求。是要商業版呢?或是OpenSource版呢? 對於一般人來說下載OpenSource版應該就可以了(此外,因為Qt目前是採取LGPL的授權,根據上次研討會Qt部門頭頭的說法,只要你最後的執行檔是動態連結Qt的程式庫,就可以開發付費的軟體)。 接著你還要決定你是要下載完整的SDK(以執行檔型式)或是只要必要的程式(以原始碼形式)就好。對於喜歡使用IDE來開發軟體的人來說,倒是可以下載完整的SDK,直接試試看裡面的Qt Creator這個IDE(當然,你也可以下載原始碼編譯出來Qt Creator))。在台灣Nokia辦的研討會中,這個IDE倒是受到相當多的注目。但是,個人淺見是沒有一定要用他的必要。一般的編輯軟體就很足夠了。而以我現在用的Ubuntu 9.04系統,Qt 4.5.0已經包含在套件庫裡,不必自己手動編譯。但是,若是想要試試看新的4.5.1的版本,就可以在這裡下載原始碼來編譯。 將壓縮檔解開後,進入目錄,執行 [josh@halo:~/qt-x11-opensource-src-4.5.0 > ./configure --help ,來看看編譯時可以用的選項。我個人大約會注意的有這幾個,
  1. -prefix:在你想將Qt安裝在特定的目錄時,可以用這個選項。通常,在一般的開發環境中,所有的開發工具會安裝在同一父目錄下,再由Make rules指定每一個Release應該使用的工具或函式庫版本。這樣的安排,主要是要避免不同開發者之間鍊結錯誤函式庫的機會。這時候,管理者就可以使用這個選項將Qt安裝在規定的目錄下。
  2. -release|-debug|-debug-and-release:是否產生偵錯版本。
  3. -shared|-static:這個選項很有意思。之前提過在LGPL下,Qt的函式庫必須被動態鍊結,也就是你的程式必須動態開啟Qt的.so函式庫。而-shared這個選項,就是編譯出一套Qt的.so函式庫。相反地,當你希望Qt的函式庫是整個包含在你的執行檔時,就可以用-static來編譯出Qt的Archived函式庫(.a),之後再連結進執行檔。這個情形下,使用ldd,就不會列出Qt的任何.so檔。
  4. -make或-nomake:通常,你可以經由這個選項指定要編譯的模組。我通常覺得不需要編譯examples和demos兩項,所以我可以把他們加在-nomake裡。
決定好參數之後,就可以開始編繹了, [josh@halo:/tmp/qt-x11-opensource-src-4.5.0 > ./configure -prefix /home/josh/qt/4.5.0 -shared -debug-and-release -nomake "examples demos translation" [josh@halo:/tmp/qt-x11-opensource-src-4.5.0 > gmake; gmake install 以我的機器,大概15-30分鐘,編譯就完成了。接著,將Qt的環境加入系統中(以bash為例), export QTDIR=/home/josh/qt/4.5.0 export PATH= "$QTDIR/bin:$PATH" export LD_LIBRARY_PATH= $QTDIR/lib:$LD_LIBRARY_PATH 現在,就可以試著執行Qt內付的工具,如assistant或是qtconfig等。

2007-07-29

Qt Programming - Callback function與signal/Slot

Event-Driven的設計:

在許多的傳統的UI設計中,經常會有所謂Callback function的設計,例如這個按鈕按下去(event)之後
需要做什麼事,是你事先並無法確定或是缺乏一些資訊來進行時,我們就必須利用Callback function先將
function pointer註冊在這個按鈕中,等到他被按下後,便執行此function。所以這個function會被稱
之為Callback function,因為是註冊後才會被呼叫。

但是,有X11/Xt 經驗的設計師就會明白Callback function的缺點有下:
  1. 缺乏function signature的檢查:Callback function是以function pointer的方式註冊,所以compiler是無法在compile的時候幫你做檢查,通常是程式在執行時才會發生錯誤。

Qt的Signal/Slot設計:


Qt的Signal/Slot機制使得programmer可以更快找出這類問題,並縮短程式開發的時間(大部分的
Programmer認為找出Bug在哪裡的時間遠大於修正他的時間)。

Qt利用moc這個類似preprocessor的程式將程式碼中的signal和slot編成可以編譯的meta object檔。
使programmer在寫程式時減少參數傳錯的機會。例如,

connect( this, SIGNAL( myButtonClicked( int, char) ),
this, SLOT( doSomething( int, char ) ) );
上面的例子中,myButtonClicked和doSomething的function signature必須完全吻合。而他們的宣
告應該如下:

class MyClass : public QObject {

Q_OBJECT

public:
/* ... */
signals:
void myButtonClicked(int, char);

public slots:
void doSomething(int, char);

private:
/* ... */

};
甚至,使用者可以在一些特定的情況下,自己發出signal,如

// 如果按鈕被按時,
emit myButtonClicked(3, 'c'); //
而在接收端,就會執行

void
MyClass::doSomething( int k, char c)
{
// k = 3, c = 'c';
}
是不是很簡單呢?

2007-07-28

Qt Programming - 發展環境

一般習慣在Windows環境工作的程式設計師常會使用IDE這類工具來編輯程式。使用與否,說實在的我個人認為並沒有甚麼好或不好,端看個人使用習慣。只是老實說在Unix/Linux下的Qt/IDE環境實在是凡善可陳。雖然是有Kdevelop這個名氣大的工具,不過我個人還是喜歡樸實一點(可能是鄉下俗吧)。因為,我是慣用Emacs的,所以當初在尋找可方便編輯Qt程式的Editor時,就只尋找有關於Qt/Emacs的資料。

雖然,KDE這個Team做了Kdevelop這個東西,但是鮮為人知的是他們也另外為了Emacs做了一個叫做kde-emacs的package。從他的名字可以知道,他是專門替在Emacs下寫Qt/KDE程式的工程師設計的。感動吧!
這套emacs的擴充套件可以從kde-sdk中取得。

此外,為了讓在Emacs下寫程式的工程師效率更高,另外也有一個好東西要介紹一下,那就是ECB了。顧名思義,就是Emacs Code Browser。若是將這兩套東西搭配起來用,其實我個人認為是遠超過商用IDE介面的。而且是跨平台。只要有Emacs的地方就可以用。

上圖就是整合起來的畫面。Cool? 用用看吧,你會喜歡他的。

Qt Programming - 序言

我想自己使用Qt來設計GUI也有兩 三年了 也累積了不少經驗 其中也不乏直接看Qt的source code來規避Qt設計上的小缺點。我想也是時候把自己的一些心得寫下來了。我想要討論的部份包括一些實際我曾經寫過的產品所使用到的技巧:
  • 基本的UI Callback 的觀念
    • 何謂Observer。
    • Qt的Signal/Slot設計方式。
  • 使用QProcess應該注意的地方。
  • 如何使用Qt的Layout來安排UI的Widgets.
  • 利用QThread發展Multithreaded的程式。
    • 何謂Command pattern。
    • 如何使用QMutex,QWaitCondition。
  • 如何利用QTcpSocket?
    • 何謂State Pattern?
    • 何謂Observer Pattern?
    • 何謂Chain of Responsibility Pattern?
  • 如何將一個Tcl的Interpreter嵌在程式中,讓你的程式是可以接受Tcl script。 大部分的CAD產品都具備這項功能。
基本上就先想到這些要寫的,再一步一步增加吧。

原則上,具備的常識
  • C++ Programming。
  • Design Pattern。
  • UNIX programming。 尤其是 IPO(inter process communication)。這在Qt或是其他的UI Library等需要event-driven的環境都非常常見。尤其是select()這個function更是哪裡都用。