2020年6月30日 星期二

在 Slider 使用 float 數值

在 Slider 使用 float 數值

前言

  在前一篇 Slider 的基本應用 裡說明了 Slider 的基本應用,但 Slider 的數值是用 Integer (整數),作為數值來儲存,如果需要用到 float 或 double 這種帶有小數的數值該如何解決呢?

內容

  先到 [ GitLab ] HelloQt 下載範例,這次應用的專案路徑
(HelloQt' directory)/Slider/FloatValue,範例執行的結果如下
範例的執行結果

左側的 Slider 是以 float 為數值,範圍在 0 ~ 10 ,右側的 Slider 是以 double 為數值,範圍在 -10 ~ 10,接著看程式的部分,看到 MainWindow::MainWindow() ,程式碼如下
  //
  float value1 = 5.0f;
  ui->horizontalSlider->setValue( value1 * 10.0f );
  ui->label1->setText( QString::number( 0.1f * ui->horizontalSlider->value() ) );
  //
  double value2 = 0.0f;
  ui->verticalSlider->setValue( value2 * 100.0 );
  ui->label2->setText( QString::number( 0.01 * ui->verticalSlider->value() ) );
  //
  connect( ui->horizontalSlider , &QSlider::valueChanged , this , &MainWindow::onHorizontalSliderValueChanged );
  connect( ui->verticalSlider , &QSlider::valueChanged , this , &MainWindow::onVerticalSliderValueChanged );

在開頭的 value1 是一個 float 的數值,當要把 float 的數值設定到 Slider 的時候先乘上 10.0f ,接著同步的 Label 是將 Slider 的數值乘上 0.1f  ,如果在設計介面看到該 Slider 的值域會是 0 ~ 100 ,如下圖
左側 Slider 的值域

利用乘上 10.0f 來把值域從 0 ~ 10 變成 0 ~ 100 ,在取 Slider 的數值的時候,要在將值域 0 ~ 100 變成 0 ~ 10 ,所以要乘上 0.1f  , double 的用法也可以這樣用,要注意的是這個方法會有精度的問題,左側的 Slider 無法拉出像是 5.57 這樣的數值,因為精度只到 0.1,右側的 Slider 的精度則是 0.01 。

參考資料

[ doc.qt.io ] QSlider Class

相關文章與資料

[ GitLab ] HelloQt
Slider 的基本應用

2020年6月23日 星期二

使用 Qt 來顯示圖片

使用 Qt 來顯示圖片

前言

  最近在 Qt 中顯示圖片,但發現工具箱裡的 UI 似乎沒有顯示圖片 widget ,在此把學習的過程做個紀錄。

內容

    先到 [ GitLab ] HelloQt 下載範例,這次應用的專案路徑
(HelloQt' directory)/Label/ShowImage,在 Qt Creator 開啟設計介面會看到以下
範例的設計介面

Qt 的顯示圖片 widget 是 Label ,圖中左側為其位置,這個設計有一些不直覺, Label 通常是顯示字的 widget ,但在 Qt 它兩個都可以用,如果需要看如何顯示字可以參考 (HelloQt' directory)/Label/Basic 。範例執行結果如下
範例的執行結果

範例的結果會顯示3張圖片,左側的圖片是在設計介面設定來自資源檔的圖片,左下則是用程式設定來自資源檔的圖片,而右上是直接用程式讀取檔案系統的圖片。

  就圖片的來源看有兩種,一是從資源檔,另一個則是檔案系統,檔案系統就是常見的讀取圖片的方法,直接用路徑開啟檔案後顯示圖片。資源檔又是什麼呢?資源檔是 Qt 自帶的打包資料手段,讀取資源的方法有點特別之後會說明。

  如果要為專案新增資源檔可以參考下圖
新增資源檔

資源檔需要命名,可以依據自己的喜好命名,加入後可以在專案瀏覽器裡看到它,如下圖
資源檔在專案瀏覽器的樣子

增加完資源檔後就來學著編輯資源檔的檔案,在專案瀏覽器的資源檔點擊右鍵,選擇"Open in Editor",就會開啟編輯介面,如下圖
開啟資源檔的編輯器

編輯器會看到下圖
資源檔的編輯介面

資源檔的編輯看起來會像是編輯檔案系統,但它不會真正在檔案系統產生檔案,程式要讀取指定資源時可以透過這個虛擬的檔案路徑來指定要讀的資源,"Prefix"可以想像是虛擬資料夾,"Add Files" 就是增加虛擬檔案,增加時會要求指定檔案系統的檔案來源,"移除"就如同字面上的意思就是刪除。範例的虛擬檔案來源在該專案之下,如下圖
來源檔案的位置

如果要讓虛擬檔案與來源檔案的名稱不同時可以更改"別名"這個屬性。

  資源檔編輯好後,如何在編輯介面指定圖片呢?如下圖
在編輯器指定圖片

就像之前所說資源來源有兩種,這裡選擇"資源",就可以看到下圖
選擇資源檔的檔案

選擇完後就可以在編輯器看到圖片的顯示。

  在程式控制方面,看到 MainWindow::MainWindow() ,程式碼如下
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  //
  QPixmap* pPixMap=new QPixmap( "../Label_ShowImage/MyDirectory/MyImage.png" );
  ui->label1->setPixmap( *pPixMap );
  //
  QPixmap* pPixMap1=new QPixmap( ":/resImage/MyImage1.png" );
  ui->label2->setPixmap( *pPixMap1 );
  //
}

"label1"就是右上角的圖,會透過 QPixmap 這個 class 來讀取圖片,這裡讀取的檔案系統的路徑,這裡會從工作目錄透過".."來返回專案目錄,可以在專案目錄下找到這個檔案。使用檔案路徑作為讀取檔案要考慮到工作目錄的問題,如果有修改過工作目錄的話這個路徑也要跟著修改。接著來看"label2",也就是左下的圖,讀取一樣透過 QPixmap  來讀取,但路徑來自資源檔的虛擬路徑,以":/"開頭做為區分,之後的路徑依據在資源檔的編輯來指定。

參考資料

[ doc.qt.io ] QLabel Class

相關文章與資料

[ GitLab ] HelloQt

2020年6月16日 星期二

CheckBox 的基本應用

CheckBox 的基本應用

前言

  應用程式常常需要作出選擇,不論是單選或多選,甚至不選,這時候 CheckBox 可以勝任這個任務,這次會說明在 UI 編輯器裡編輯與用程式來編輯的作法,在此做個紀錄。

內容

  先到 [ GitLab ] HelloQt 下載範例,這次應用的專案路徑
(HelloQt' directory)/CheckBox/Basic,在 Qt Creator 開啟設計介面會看到以下
範例的設計介面

圖中左側為 CheckBox 在工具箱的位置。執行結果如下
範例的執行結果

範例會在按下"Result"的時候顯示偵錯訊息,內容是三個 CheckBox 是被按下,在"Option1"的 CheckBox 的選擇改變時也會顯示偵錯訊息,這個事件的綁定可以用在如"全選"或"全不選"這樣的應用。

  在程式控制方面,看到 MainWindow::MainWindow() ,程式碼如下
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  //
  connect( ui->pushButton , &QPushButton::clicked , this , &MainWindow::onPushButtonClicked );
  connect( ui->checkBox1 , &QCheckBox::stateChanged , this , &MainWindow::onCheckBox1StateChanged );
  //
  ui->checkBox1->setChecked( true );
}

開頭會綁定 CheckBox 的事件,接著是透過 setChecked() 來設定 CheckBox 的選擇,要注意這行發生在事件綁定之後,所以這行執行後會啟動 onCheckBox1StateChanged() 。看到 onPushButtonClicked() 的部分,程式碼如下
void MainWindow::onPushButtonClicked( bool clicked )
{
  qDebug( "Option1:%s" , ui->checkBox1->isChecked() ? "Y" : "N" );
  qDebug( "Option2:%s" , ui->checkBox2->isChecked() ? "Y" : "N" );
  qDebug( "Option3:%s" , ui->checkBox3->isChecked() ? "Y" : "N" );
}

透過 isCheck() 可以得到該 CheckBox 的選擇狀態,想當好懂。

參考資料

[ doc.qt.io ] QCheckBox Class

相關文章與資料

[ GitLab ] HelloQt

2020年6月10日 星期三

ComboBox 的基本應用

ComboBox 的基本應用

前言

  在應用程式中常常需要作出多選一的動作,在 Qt 可以用 ComboBox 來實現,這次會說明在 UI 編輯器裡編輯與用程式來編輯的作法,在此做個紀錄。

內容

  先到 [ GitLab ] HelloQt 下載範例,這次應用的專案路徑
(HelloQt' directory)/ComboBox/Basic,在 Qt Creator 開啟設計介面會看到以下
範例的設計介面

圖中的左下是 ComboBox 在工具箱的位置。執行結果如下
範例的執行結果

範例的 PushButton 是用來模擬讀取 ComboBox 的內容的情形,在按下後讀取 ComboBox 的內容顯示偵錯訊息,並在每次 ComboBox 的內容改變時也會顯示偵錯訊息。在設計介面雙擊 ComboBox 會出現編輯內容的介面,如下圖
ComboBox 的內容編輯介面

介面的左下方有新增與刪除選項的按鈕,中下方的按鍵可以控制選項的順序,用起來相當直覺簡單。

  接著來看看程式的操作,先看到 MainWindow::MainWindow() ,程式碼如下
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  //
  ui->comboBox->addItem("MyAddOption");
  ui->comboBox->insertItem(2,"MyInsertOption");
  //
  connect( ui->pushButton , &QPushButton::clicked , this , &MainWindow::onPushButton_Clicked );
  connect( ui->comboBox , QOverload<int>::of( &QComboBox::currentIndexChanged ) , this , &MainWindow::onComboBoc_CurrentIndexChanged );
  //Force select option by index
  //ui->comboBox->setCurrentIndex(1);

  //Force select option by string
  //ui->comboBox->setCurrentText("Option1");
}

開頭會先用程式的方式新增選選項,有分為"add"與"insert","add"就是加在最後很好理解,"insert"會多一個參數,就是 index ,這個 index 是指"第幾個選項", ComboBox 的 index 指的是第幾個選項,從 0 開始編號,所以不存在重複的 index 的問題。事件綁定的部分範例在綁定 QComboBox::currentIndexChanged 的時候要經過類似轉型的動作,可以在 [ doc.qt.io ] QComboBox Class 裡找到說明,看到讀取 ComboBox 的內容的部分,以MainWindow::onPushButton_Clicked() 為例,程式碼如下
void MainWindow::onPushButton_Clicked(bool clicked)
{
  qDebug( "Result text:%s" , ui->comboBox->currentText().toLocal8Bit().data() );
  qDebug( "Result index:%ld" , ui->comboBox->currentIndex() );

}

讀取透過 currentText() 與 currentIndex() ,就如同字面上的意思,一個讀文字,另一個讀取索引,想當好懂。如果要透過程式來選擇 Combox 的選項可以用 setCurrentIndex() 與 setCurrentText() ,就如同字面的意思,一個透過 index 選擇另一個透過字串。

參考資料

[ doc.qt.io ] QComboBox Class

相關文章與資料

[ GitLab ] HelloQt

2020年6月1日 星期一

MenuBar 的基本應用

MenuBar 的基本應用

前言

  這次來說明應用程式視窗常出現的選單如何在 Qt 裡編輯,這次會說明在 UI 編輯器裡編輯與用程式來編輯的作法,在此做個紀錄。

內容

  先到 [ GitLab ] HelloQt 下載範例,這次應用的專案路徑
(HelloQt' directory)/MenuBar/Basic,在 Qt Creator 開啟設計介面會看到以下
範例的設計介面

執行的結果如下
範例的執行結果

範例會在每次按下以 action 為開頭的選項後顯示偵錯訊息,也會在城市開始時顯示一些偵錯訊息。在設計的介面要新增選項,可以在下圖
在設計介面新增選項

雙擊該處就可以輸入選項的名稱,並且可以在物件視窗裡看到它在"menubar"裡被新增,型態可能是 QMenu 或 QAction ,就看它有沒有在 Child 裡新增來決定,如下圖
在物件視窗裡狀況

接著來看如何在程式操作,先看到 MainWindow::MainWindow() ,程式碼如下
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  //manual add
  //Don't use follow
  //QMenu* pMyMenu = (QMenu*)ui->menubar->addMenu( new QMenu( "MyMenu" ) );
  QMenu* pMyMenu = ui->menubar->addMenu( new QMenu( "MyMenu" ) )->menu();
  QAction* pMyAction = new QAction( "MyAction" );
  pMyMenu->addAction( pMyAction) ;

  //Get actions
  //Don't use follow
  //QMenu* pOption = (QMenu*)ui->menubar->actions().at(0);
  QMenu* pOption = ui->menubar->actions().at(0)->menu();
  qDebug( "%s" , pOption->title().toLocal8Bit().data() );
  //
  QMenu* pGroup = pOption->actions().at(0)->menu();
  qDebug( "%s" , pGroup->title().toLocal8Bit().data() );
  //
  qDebug( "%s" , pGroup->actions().at(0)->text().toLocal8Bit().data() );
  qDebug( "%s" , pGroup->actions().at(1)->text().toLocal8Bit().data() );
  qDebug( "%s" , pOption->actions().at(1)->text().toLocal8Bit().data() );

  //Bind event
  connect( pGroup->actions().at(0) , &QAction::triggered , this , &MainWindow::onAction1Triggered);
  connect( pGroup->actions().at(1) , &QAction::triggered , this , &MainWindow::onAction2Triggered);
  connect( pOption->actions().at(1) , &QAction::triggered , this , &MainWindow::onAction3Triggered);
  connect( pMyAction , &QAction::triggered , this , &MainWindow::onMyActionTriggered);
}

範例的開頭會手動新增"MyMenu"與"MyAction",這和 UI 的操作時不一樣,並不會自動判定是 QMenu 與 QAction ,所以要自己指名,在 addMenu() 的時候會回傳新增的 QMenu ,但會發現回傳的型別是 QAction ,這裡一定要注意 QAction  與 QMenu 並不是繼承關係,但是雙方卻互相提供轉型的 function ,範例透過 menu() 來將 QAction  轉型回 QMenu ,千萬別用 C 的轉型硬幹。接下來是取得每個 action ,最開始會透過 QMenuBar::actions() ,它回傳的型別是 QList<T> ,這個型別用法跟 std::list<T> 差不多,這裡就不多做說明了,回傳後在透過之前說的轉型來取得 QMenu ,範例透過偵錯訊息將其選項名稱顯示,在"Option"裡的"Group"可以透過現在的 QMenu 裡的 QMenu::actions() 來取得,和之前的原理是一樣的,這樣就可以取得整個樹狀結構的選單。最後是事件綁定的部分,這部分就和一般的事件綁定一樣,只是來源的型別是 QAction 。

  最後要說的是 UI 的物件視窗的問題,不知道是不是 Bug ,如果物件型別是 QAction 的時候,右鍵選單會跳不出來,也無法透過 Delete 鍵來刪除,這會造成無法在 UI 操作的時候作"刪除"的動作。

參考資料

[ doc.qt.io ] QAction Class

相關文章與資料

[ GitLab ] HelloQt