Fork me on GitHub

10/27/2010

Qt 環境建構指南 - environment setting

最近對於跨平台 GUI 有些興趣,於是就找了 Qt 來玩玩,希望可以做出橫跨 Windows, Linux 和 Mac 的跨平台程式。

記錄一下 Windows 下的 Qt 環境建置,其實 Qt 的官方網站已經提供許多簡單的安裝包,除了使用開源的 GCC compiler 以外,假如有安裝 VS2008 的話,也可以直接下載 「Qt libraries 4.7.0 for Windows (VS 2008, 226 MB)」。

安裝完以後,預設的路徑是在 「C:\Qt\4.7.0\」,當中已經包含預先建置好的範例專案,以及執行檔。直接進入「C:\Qt\4.7.0\examples」探索他的範例程式。在此之前要先手動設定好「環境變數」。

進入 Windows 的環境變數設定,並且在 PATH 當中加入 「C:\Qt\4.7.0\bin;」,注意:不同路徑之間以分號隔開,並且不能多加空格!設到好之後,可以選一個 project 來試跑看看,例如:calculator 專案。



另外,Qt 也提供了 Visual Studio Add-in,安裝之後,VS 當中就會新增建置 Qt 專案的選項,有一些預先提供的 project template 可供使用。

...

10/26/2010

封裝 openCV 事件成物件的方法成員 - event encapsulation

在使用 openCV 提供的 highgui 時,其提供了一個簡單的滑鼠鍵盤事件機制,透過 cvSetMouseCallback 將 on_mouse 事件綁定到 window_name 視窗。



CVAPI(void) cvSetMouseCallback( const char* window_name, CvMouseCallback on_mousevoid* param CV_DEFAULT(NULL));


一旦 window_name 視窗發生動作就會驅動 on_mouse 事件方法,但是這個 on_mouse 方法不能是類別的方法成員 ( 例:object->on_mouse ),嘗試後發現,可以利用函數指標將 on_mouse 方法 assign 成 object 的函數指標成員,這樣就可以成功的將事件方法封裝到類別之中。


// ctrl.h

typedef void (*pFun)(int, int, int, int, void*);

class Controller {
public:
  Controller();

  pFun pFun1;
};



// ctrl.cpp

#include <iostream>
#include <highgui.h>
#include "ctrl.h"

void on_mouse( int event, int x, int y, int flags, void *param )
{   
  if( event == CV_EVENT_LBUTTONDOWN )
    std::cout << "LBUTTONDOWN  occurs in the window" << std::endl
}

Controller::Controller()
{
  pFun1 = &on_mouse;
}



// main.cpp

#include <highgui.h>
#include "ctrl.h"

int main()
{

  Controller controller;

  cvNamedWindow("src", 1);
  cvSetMouseCallback( "src", controller.pFun1, 0 );

  while(1) {
    int c = cvWaitKey(30);
    if ( (char)c == 27 ) {
      cvDestroyWindow( "src" );     
      break;     
    }
  }
}


實作之後發現,此法依舊行不通,單純的函式指標 (如上) ok。但是,成員函式指標 依然無法 work,最後的解決辦法是將 on_mouse 變成一個 cpp 的全域變數,然後再用 friend 使其可以存取類別的私有成員...

...

10/12/2010

用 Google Code 作專案的版本控制

Google Code 上頭除了有許多 open source project 可以挖寶,它也是一個免費的專案 hosting 和版本控制的好工具!


參考資料:

如何將資料夾移除版本控制:http://tortoisesvn.net/node/343
TortoiseSVN 使用簡介:http://www.dev.idv.tw/mediawiki/index.php/TortoiseSVN 使用簡介

......

10/02/2010

[iPhone] 了解 PhotoPicker 當中的委派機制

最近想要實作一個 iPhone 手機上的照相軟體,因此稍微研究了一下有關 camera 相關的資料。首先 iPhone 當中處理 camera 的主要是 UIImagePickerController 這個 class。利用 UIImagePickerControllerDelegate 和 UIImagePickerController 就可以開始處理/控制 iPhone 的 camera 和 photo library。

在 Beginning iPhone3 Development 書中,關於 Camera 的章節範例,主要是以 UIViewerController 下的 ModalView ( - (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated ) 模式來呈現擷取到的照片,這個模式下的照片並非全螢幕,仍保留一些 Nav Bar 或者 Tool Bar,跟一般看到的 app 可以在拍照完以後在全螢幕模式下編輯不太一樣。

在 Apple Developer 網站當中有一個 PhotoPicker 的範例,主要就是在演示,如何不使用 ModalView 的方式取得 camera 所拍攝到的原始影像,在將這個影像填入你要呈現的 View 當中。

該範例當中宣告了兩個 ViewController:MyViewController 和 OverlayViewController,前者主要就是客製化的 View 想要用來避開 ModalView 模式的方式。後者的 .h 如下程式碼宣告,這個 class 當中包含了一個 UIImageViewController 並且還有一個 遵守 OverlayViewControllerDelegate 協定的成員 "delegate"。

@protocol OverlayViewControllerDelegate;

@interface OverlayViewController : UIViewController <UINavigationControllerDelegate, 
UIImagePickerControllerDelegate>
{
    id <OverlayViewControllerDelegate> delegate;
    
    UIImagePickerController *imagePickerController;
    
@private
    ...
}    

@property (nonatomic, assign) id <OverlayViewControllerDelegate> delegate;
@property (nonatomic, retain) UIImagePickerController *imagePickerController;

...

@end

@protocol OverlayViewControllerDelegate
- (void)didTakePicture:(UIImage *)picture;
- (void)didFinishWithCamera;
@end


可以看到這個 OverlayViewControllerDelegate 當中列出了兩個必要實現的方法 didTakePicture 和 didFinishWithCamera。這兩個方法的名稱看起來像是系統發出的事件,但是先前提到,有關照相相關的任務主要是以 UIImagePickerController 這個 class 所控制,所以來看看 OverlayViewControllerDelegate 的 .m 檔。

#pragma mark -
#pragma mark UIImagePickerControllerDelegate

// this get called when an image has been chosen from the library or taken from the camera
//
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
    
    // give the taken picture to our delegate
    if (self.delegate)
        [self.delegate didTakePicture:image];
    
    if (![self.cameraTimer isValid])
        [self finishAndUpdate];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    [self.delegate didFinishWithCamera];    // tell our delegate we are finished with the picker
}

@end

可以看到在實現 UIImagePickerControllerDellegate 的兩個方法當中,偷偷地把事件和影像的資訊 委派給 OverlayViewControllerDelegate protocol 的方法,那麼誰負責做這個 protocol 當中描述的這兩件事呢,答案就是 MyViewController!

- (void)viewDidLoad
{
    self.overlayViewController =
        [[[OverlayViewController alloc] initWithNibName:@"OverlayViewController" bundle:nil] autorelease];

    // as a delegate we will be notified when pictures are taken and when to dismiss the image picker
    self.overlayViewController.delegate = self;
    
    self.capturedImages = [NSMutableArray array];

    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {
        // camera is not on this device, don't show the camera button
        NSMutableArray *toolbarItems = [NSMutableArray arrayWithCapacity:self.myToolbar.items.count];
        [toolbarItems addObjectsFromArray:self.myToolbar.items];
        [toolbarItems removeObjectAtIndex:2];
        [self.myToolbar setItems:toolbarItems animated:NO];
    }
}


// as a delegate we are being told a picture was taken
- (void)didTakePicture:(UIImage *)picture
{
    [self.capturedImages addObject:picture];
}

// as a delegate we are told to finished with the camera
- (void)didFinishWithCamera
{
    [self dismissModalViewControllerAnimated:YES];
    
    if ([self.capturedImages count] > 0)
    {
        if ([self.capturedImages count] == 1)
        {
            // we took a single shot
            [self.imageView setImage:[self.capturedImages objectAtIndex:0]];
        }
        else
        {
            // we took multiple shots, use the list of images for animation
            self.imageView.animationImages = self.capturedImages;
            
            if (self.capturedImages.count > 0)
                // we are done with the image list until next time
                [self.capturedImages removeAllObjects];  
            
            self.imageView.animationDuration = 5.0;    // show each captured photo for 5 seconds
            self.imageView.animationRepeatCount = 0;   // animate forever (show all photos)
            self.imageView.startAnimating;
        }
    }
}


上面 MyViewController 實現碼當中可以看到,他包含了一個 OverlayViewController 物件,並且他將該物件的代理設定為 "自己" ( self.overlayViewController.delegate = self; ),最後他實現了這個 OverlayViewControllerDelegate 這 protocol 的兩個方法,將 UIImagePickerController 得到的影像資料神奇的存到自己的成員 capturedImages 當中。

簡而言之,OverlayViewController 將 UIImagePickerControllerDelegate 和 UIImagePickerController 包裝起來,所以富有預設的圖片顯示功能,但是他並沒有用 Modal 的方式,而是將他取得的照片,傳給自己的 delegate 成員。而 MyViewController 有一個 OverlayController 成員,又將自己指向 OverlayController 的 delegate 成員。因此等效於 UIImagePickerController 把取得的照片傳給 MyViewController。

......