2009年12月19日

說 class 太多的人, 也會說 class 太少

因曾經寫過 Java 程式, 在當時的 Leader 為了彈性, 而利用眾多 Frameworks 再加上自己的創意打造出一個看起來不錯的程式架構, 不過當時初出社會的我倒是挺感冒的, 因為當時為了要下一道 SQL 的效果, 而必須要更動 10 個程式檔或 XML 檔。

講白一點就是,你今天要在網頁上寫一個新增使用者的頁面,所花的功夫可謂非常的不小。雖然我本人是贊同架構的重要,以及對重覆程式碼特別厭惡,但一個小小的動作需要大費周章,這對一個程式設計師不到10個人的軟體公司而言,個人覺得不是一件好事。

因此如果是自己的專案,總是希望去達到平衡點。

話說之後到了某個公司之後, 居然有個網路/通訊產品的輔助程式(就是utility,在電子公司最不被重視的一塊)要用Java來弄, 公司的其它工具大多是用BCB寫的, 而因為我之前寫過Java, 加上這個程式要用WEB當UI,所以就交給我了。不過這個專案主要是在 sockets上,所以UI方面我不太想用HTML/JSP,甚至是之前用的 frameworks"們"(struts,hibernate,spring,webwork),怕要花太多時間,所以不如學一下 Adobe 的 Flex, 用flash來做前端 UI...

因為怕以後接手的人不好維護, 所以一切從簡, class也不敢弄得太複雜(反正有人就是覺得全部的程式寫在同一個function最好...Orz...), 不過沒被那些 frameworks搞過的人還是覺得 class太多, 主要是公司裏主要是寫 C 程式, 雖然會用 C++編譯器,但還是會用 C 的想法去寫

雖然本人基本上沒什麼特別偏好 Java 或 C/C++, 或那一種 framework, 目前唯一"不太喜歡"的是 MFC ,哈...反正只要能快速及正確的完成任務就是好"工具"(所以現在的需求有了跨 Linux/Win/WinCE/Embedded我才用 QT, 用之前並沒寫過 QT..)。

話說這個案子第一版之後, 中間接了一個 Firmware 維護, 再來是另一個新的 utility, 要用 BCB 重新寫的, 這時我又更精簡的使用 class 數, 當然每個 class 會變得很肥, 因為程式碼多嘛..

這時我又聽到另一種聲音, class太少.........XD

哇咧, 這要我怎麼辦?!

所以"說 class 太多的人, 也會說 class 太少"啊...

其實 class 多少並不是重點, 更不是問題! 而是你想不想去了解程式才是最大的問題啊!

BCB 6 安裝後的二件事

1.請到 Tools -> Editor Options 在第一頁(General)Tab把 Undo after save打勾, Undo可是在開發過程中, 所能記憶最短程式片段的保存方式!!(應該沒有人寫幾行就commit到版本管理系統的吧?!)

2.如果你的程式有用到第三方元件, 請先到 ${BCB}/Lib安裝dclusr.bpk

如果在安裝元件時, 編譯時發生 TCustomOutline.. Link Error錯誤訊息, 請把 ${BCB}/Lib/bcbsmp.bpi 加到 requires 裏


註:${BCB}指的是BCB安裝目錄

2009年12月18日

QWT4.5.6 遇到QT 4.6

打算將開發中的專案升級到 QT4.6, 因為有用到 QWT, 所以順便一起升級, 結果在編譯QWT時, 用VC2005 編譯一直出現 qHash()..的錯誤訊息, 結果在網上看到一串滿"激烈"的討論串

QWT原作者與 QT Senior Product Manager的對答
http://www.mail-archive.com/qt4-

preview-feedback@trolltech.com/msg01358.html


最後沒時間研究 WHY 的我, 只好乖乖到 qwt_valuelist.h 把47~49行註解掉

// MOC_SKIP_BEGIN
//template class QWT_EXPORT QList;
// MOC_SKIP_END


不過以我的"嫩"英文看起來, 這位"Product Manager"還滿強硬與有程式底子的啊!


---話說要將 QWT 以DLL型式使用時, 請在你的專案中加一個定義QWT_DLL

[QT] Print widget && Save widget to image file

1.Print QWidget

QPrinter printer(QPrinter::ScreenResolution);
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(tr("Print Document"));

if (dialog->exec() != QDialog::Accepted)
return;

QPainter painter;
QPixmap pix = QPixmap::grabWidget(ui.tabWidget->currentWidget());
painter.begin(&printer);
painter.drawPixmap(0,0,pix);
painter.end();


2.Save QWidget to image file

QPixmap pix;
pix = QPixmap::grabWidget(ui.tabWidget->currentWidget());

QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),"",tr("Images(*.jpg)"));

if(!fileName.isEmpty()) {
if(!pix.save(fileName,"JPG",100)) {
QMessageBox::warning(this,tr("Error"),tr("Can not save image file!"));
}else {
QMessageBox::information(this,tr("Info"),tr("Save OK."));
}
}

2009年12月16日

拖拖拉拉1

底下是參考 Using Drag and Drop with Item Views 章節

以往在 List, Tree, Table 元件中的拖拉, 除非其 GUI Framework有提供"幫你做到好"的服務, 否則並不是一個簡單的任務

而在 QT 當中, 雖不是很簡單到不用寫程式, 但其用 override function的方式, 讓我們去覆載"拖拉"的事件, 去完成我們的自己拖拉實作函式, 相信這種作法對 OOP 而言不但是直覺而且是富有彈性的方式, 而且通常我們在拖拉的過程中, 多半會去做一些動作, 如存取資料庫等等。

最近在一個專案中, 便繼承了 QTreeWidget 及 QTableWidget , 去實作拖拉函式, 而只要是繼承自 QAbstractItemView的類別都有支援 drag-and-drop, 其實也不用懂得太多, 只要覆載以下這個函式就可以了

QDragEnterEvent 拖拉物件進入可以置放的地方時...
QDragMoveEvent 拖拉物件移動時...
QDropEvent 放下拖拉的物件...

像我就在這些事件中處理一些事情, 以及把使用者拖拉的結果存到資料庫...

另外一些元件的屬性也要設定
如QT說明文件中的範例

QListWidget *listWidget = new QListWidget(this);
listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
listWidget->setDragEnabled(true);
listWidget->viewport()->setAcceptDrops(true);
listWidget->setDropIndicatorShown(true);

listWidget->setDragDropMode(QAbstractItemView::InternalMove);


當然, 如果你不需要捕抓"拖拉事件", 直接在 QT Designer中按一按就可以了!!!!

接下來還有一些更進階的拖拖拉拉...要學習...

2009年12月15日

BCB free component

EkszBoxVCL
http://sourceforge.net/projects/ekszbox-vcl/

JVCL
http://jvcl.delphi-jedi.org/


Note:
如果是使用 BCB 6 的話, 想裝 EkzBoxVCL, 請用新增 Package的方式, 把它的 *.pas 檔加進去即可編譯及安裝

QT 移除 menu

QMenuBar 有 addMenu() 函式(話說其實我是用 designer加的), 卻沒有 removeMenu(), 真是奇怪, 取得 menu obj去 hide() or close()無解, 查詢 google 大神之後, 原來可用 setTitle("") 方式去隱藏某個 menu

話說為什麼加了 menu 之後想移掉~~但又想保留給以後使用, 這個問題很難解~的~啊!?
其實做有GUI程式最難的部分在於..."做決定的人"都有心目中最 User-Friendly 的操作方式, 可是偏偏他們都不用寫程式...

2009年12月3日

讓 jom 解放編譯 QT!

什麼時候你會喜歡 CPU 使用率 100%?

打報告的時候? NO!

寫程式的時候? NO! NO!

...看迷片的時候? NO! NO! NO!

我知道其中的一個答案便是編譯 QT framework 的時候啊~~
要苦等 2~4 小時真是叫人難受, 而且還有可能發生編譯錯誤, 重頭再來啊~

只要是使用 VC 的 nmake 去編譯, 不管你的PC有幾核心, 統統最多只會用到 1 核心, 所以在 4 核心的 Q6600 上, 在編譯 QT 時, 看到 25% 的CPU使用率, 真是苦笑不得..

幸好有 google 大神, 讓我找到 jom (關鍵字 qt jom)
而最新版的 jom binary都會放在ftp://ftp.qt.nokia.com/jom/

jom 專案首頁http://qt.gitorious.org/qt-labs/jom

一執行下去會出現

jom 0.8.1 - empower your cores

整個感覺只能用"帥啊!老皮!" 來形容, 編譯時間大幅縮短, 不到40分鐘就搞定

哈, 就用 jom 取代 nmake 吧, 底下是我在編譯 QT 4.6 for wince 的畫面(話說QT4.6 在09/12/2 正式 release, 真是超有活力的 Framework, 相較起 BCB, MFC, 以 C++ GUI Framework來說, 真是活力百倍啊..)



相關鏈結:
http://www.ffuts.org/blog/compile-qt-45-for-visual-studio-using-your-multi-core-processor/

我用的編譯組態:
configure -no-qt3support -no-opengl -platform win32-msvc2005 -no-libtiff -no-dbus -no-phonon -no-phonon-backend -no-webkit

2009年12月1日

[QT] 使用到 plugin , 要散佈程式時注意事項

在 QT 中有些看似簡單的事, 還是需要一些步驟才能順利完成

初學QT, 就幫忙別部門開發程式, 到收尾階段進行補上 icon 圖示, 結果安裝在別台電腦, 發現 icon 都跑不出來, 即使確定這些 icon 都有被當成 resource 包在執行檔裏, 後來查了 QT Reference 才發現 icon 這種圖形格式, 也是屬於一種plugin, 所以當使用 dynamic link QT時, 這些 dll 也要部署過去

在 qt\plugins下就有依目錄當作分類的各式 plugin, 如果僅是 icon, 便屬於 imageformats\qico4.dll, 安裝到主程式同目錄下的 plugins\imageformats\qicon4.dll 就可以了


如果是使用 static link QT, 需要用巨集 Q_IMPORT_PLUGIN 讓 QT 知道在編譯時, 要將這些 plugin link進主程式,


#include < QtPlugin >

Q_IMPORT_PLUGIN(qico)
int main(int argc, char *argv[]) {
.........
}



不過事情有那麼簡單, 就不需要"師程工"啦我的開發環境是 VS2005 + QT VS plugin 來開發 QT application, 至於為什麼用 VS2005, 一切只是習慣問題(看來得改?), 在這個 app 安裝在使用者電腦上之後, 所有圖示依然是出不來, 當下覺得奇怪, 不是都依照文件把該搬的 dll 都搬過去了嗎? 包含 VS2005的 C/C++ runtime library, 然後我再次查詢文件中的 Deploying an Application on Windows 章節, 嘗試了使用 QApplication::addLibraryPath()去設定路徑, 然後用libraryPaths()印出所有 QT搜尋 DLL 的路徑, 圖示還是出不來, 在浪費了1小時之後, 最後沒有用 Shared QT Libary , 還是用 static QT Library.....(難怪 Google Earth也是這樣子用), 這時第一次感覺 QT 有點難搞.然後時間經過了一個月, 在開發另一個 app 之後還是遇到相同問題, 不過這個 app 不能用 static QT library, 因為雖然是免費使用, 但掛上公司的名字,還是要遵守 QT 的licence-使用LGPL的話, 不能用 static QT, 所以時間依舊又浪費了1個小時...只好再求助 Google 大神, 發現了以下的討論串, 還滿精采的

http://lists.trolltech.com/qt-interest/2007-02/thread00449-0.html

裏面提到有人跑去問 QT 人員, 說是如果使用 VS2005 去編譯 QT 及 QT 程式的話, plugin都載入不了, 這是和 QT plugin 去搜尋 VC C/C++ Runtime Library DLL(CRT)有關係, QT plugin用到的 CRT 只會從 local 目錄去找 (windows/system32), 如果找不到就會標示此 plugin 載入失敗, 下次也不會重新當試載入, 而解決辦法是不要將 CRT 放到跟執行檔同目錄的方式去包裝安裝程式, 而是用 CRT的安裝程式 vcredist_x86.exe(可以從網站上下載, 或是在 VS2005目錄$\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\vcredist_x86\

所以情況變成, 你的安裝程式先要執行這個安裝檔, 讓 user 去安裝, 再安裝自己的程式, 這樣子 plugin就會順利載入然後有人問, 他的程式是放在 USB 隨身碟裏的, 而且使用者不一定有權限安裝(也就是綠色軟體啦), 那該怎麼辦?!


後來又有人提到 CRT 放到 某 plugin 目錄下就能解決了, 但這樣子不是每個plugin的目錄都要放那些 dll 嗎?

而且QT plugin dll一定要放在 /plugins類別/ 底下..

就快放棄的時候...
想說如果把 CRT 的 Microsoft.VC80.CRT.manifest copy到 plugin目錄中, 然後把裏面的 file tag
< file name="msvcr80.dll"..

改成相對路徑

< file name="../../msvcr80.dll"

再使用 QApplication::addLibraryPath() 把 plugin 目錄設定好
Yeah! 可以動也, copy一個文字檔總比copy 3個dll好...暫時先這樣子, 會不會有其它故事就不知道了...



在2009/12/13-------果然此法在Windows Vista/7上失效--------哈!
還好這些 DLL 不算大, 不過一想到只不是要在應用程式裏使用到ICON / JPG / GIF就要搞得大費周章, 真的滿鳥的...