1. 程式人生 > >Qt主介面獲取對話方塊資料

Qt主介面獲取對話方塊資料

在編寫Qt程式的時候,我們常常需要通過對話方塊來獲取使用者的輸入資料,比如通過檔案對話方塊獲取檔案的路徑,通過顏色對話方塊獲取使用者所選擇的顏色,這些對話方塊的類都是Qt幫我們寫好了的,呼叫相應函式就能直接返回使用者的輸入,比如顏色對話方塊QColorDialog中有一個靜態函式getColor,我們直接呼叫該函式,便會彈出顏色對話方塊,等我們選擇好顏色並確定,該函式就會返回一個QColor的物件,這個物件就包含了我們之前所選顏色的RGB值了。

然而,很多時候,我們需要建立自己的對話方塊,我們不能呼叫現成函式來獲取使用者輸入,本文將提供兩種方法,通過對話方塊來獲取使用者輸入的案例。在此之前,我們先討論一下顯示對話方塊的兩個函式,一個是show(),一個是exec()。show() 顯示的是非模態視窗,不會阻塞程式的執行緒,因此如果你的對話方塊是建立在棧上,跳出作用域之後,物件便銷燬了,因此你會發現對話方塊一閃而過;如果你用new關鍵字將對話方塊建立在堆上,跳出作用域之後物件不能被銷燬,但是建立在堆上需要考慮及時釋放記憶體的問題,以免造成記憶體洩漏。但是能夠正常顯示視窗不代表能夠很方便地獲取資料,show()不會阻塞執行緒,因此可能使用者還沒來得及輸入資料,就已經執行之後的程式碼了。解決這個問題需要用到訊號槽機制,具體解決方案會在下文詳細講解。exec()顯示的是模態視窗,它開啟了一個事件迴圈,會阻塞程式的執行緒,函式返回之後,我們直接可以獲取對話方塊的資料。下面考慮這兩種不同的對話方塊顯示方式,提供兩種不同的獲取對話方塊資料的方法。

方法一
首先考慮簡單的,使用exec()顯示對話方塊。我們定義了一個主介面的類,叫MainWindow,介面包含一個名為btn的按鈕(用於跳出對話方塊)和一個名為label的標籤(用於顯示從對話方塊獲取的使用者輸入);我們還定義一個對話方塊類,介面包含一個名為lineEdit的單行文字框(用於接收使用者輸入),以及確定和取消按鈕(這兩個按鈕是建立對話方塊的時候自動生成的)。兩個介面如下圖:
主介面
對話方塊介面
關鍵程式碼如下:

//in mainwindow.h
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow
(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; void showDialog(); }; //in mainwindow.cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //“顯示對話方塊”按鈕與顯示函式建立訊號槽關係 connect(ui->btn, &QPushButton
::clicked, this, &MainWindow::showDialog)
; } MainWindow::~MainWindow(){delete ui;} void MainWindow::showDialog() { Dialog dialog; dialog.exec(); ui->label->setText(dialog.getinput()); }
//in dialog.h
class Dialog : public QDialog
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    QString getinput();
private:
    Ui::Dialog *ui;
};

//in dialog.cpp
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
}
Dialog::~Dialog(){delete ui;}
QString Dialog::getinput()
{
    QString s = ui->lineEdit->text();
    return s;
}

程式碼說明:上面的程式還是比較容易理解的,在mainwindow.h和mainwindow.cpp裡,先將btn與showDialog建立聯絡,在showDialog內部建立Dialog物件,並通過exec()顯示,由於exec()會阻礙執行緒,因此待使用者輸入資料之後再執行後續獲取資料的程式碼,由於我們想獲取的dialog內的資料是私有的,因此在Dialog類定義了一個public的getinput()函式(之前還考慮用友元,感覺被自己蠢哭了),間接獲取使用者的輸入,最後將資料顯示在主介面的label上面,達到主介面獲取對話方塊資料的目的。
附:方法一原始碼

方法二:
上面討論的是用exec()顯示對話方塊的情況下獲取使用者輸入資料,那如果用show()顯示對話方塊,該如何獲取資料呢?由於show()不會開啟事件迴圈,因此如果繼續按上面的方法,使用者根本來不及輸入資料,後續的程式碼就已經執行了,因此需要用到訊號槽機制。思路是這樣的:按下對話方塊的確定按鈕後,程式會自動呼叫QDialog::accept()函式,因此如果我們可以過載accept()函式,在其中傳送訊號,關聯該訊號的槽便會響應,我們在槽裡面進行資料資料接收。
關鍵程式碼如下:

//in mainwindow.h
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
    void showDialog();
    void displayData(QString data);
    void accept();
};

//in mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->btn, &QPushButton::clicked, this, &MainWindow::showDialog);
}
MainWindow::~MainWindow(){delete ui;}
void MainWindow::showDialog()
{
    Dialog *dialog = new Dialog(this);
    connect(dialog, &Dialog::receiveData, this, &MainWindow::displayData);
    dialog->show();
}
void MainWindow::displayData(QString data)
{
    ui->label->setText(data);
}
//in dialog.h
class Dialog : public QDialog
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
signals:
    void receiveData(QString s);
private:
    Ui::Dialog *ui;
    void accept();
};

//in dialog.cpp
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
}
Dialog::~Dialog(){delete ui;}
void Dialog::accept() //過載accept()
{
    QString data = ui->lineEdit->text();
    emit receiveData(data);  //傳送訊號給mainwindow
    QDialog::accept();
}

程式碼說明:使用者輸入資料後,按下確定按鈕,程式會自動呼叫accept(),因此過載了accept()函式,讓其將獲取的輸入資料作為訊號(receiveData是一個訊號)通過emit傳送給主介面,在mainwindow.cpp,我們訊號receiveData和槽displayData進行關聯,displayData將接收的資料顯示在主介面的label上的。總的來說,資料輸入後,先呼叫accept(),accept()將訊號(訊號上帶有資料)傳送給displayData,displayData顯示資料。通過訊號槽機制,我們看到,即使對話方塊作為非模態視窗顯示,即使其稍縱即逝,我們還是能通過特定手段獲取使用者的輸入。
附:方法二原始碼

執行結果:
執行結果