參考 https://wiki.qt.io/Install_Qt_5_on_Ubuntu .php
# 安裝g++
sudo apt install build-essential # sudo apt install libfontconfig1 # 安裝openGL支持 sudo apt install mesa-common-dev libglu1-mesa-dev
從ustc鏡像直接下載安裝包, 地址是 http://mirrors.ustc.edu.cn/qtproject/official_releases/qt/5.11/5.11.1/mysql
執行chmod u+x使其可執行linux
直接運行 qt-opensource-linux-x64-5.11.1.run, 會出現安裝界面, 這一步能夠配置網絡代理, 往下進行須要填寫本身在QT註冊的帳戶和口令, 會進行在線驗證.git
設置安裝目錄時, 能夠將路徑配置到/opt下, 例如 /opt/qt/Qt5.11.1, 會在最後一步時彈出提示輸入su口令.github
組件選擇: 若是空間足夠的話, 除了一個deprecated的之外, 都選上吧. 實測, 整個安裝下來佔地5.4GBredis
而後就能夠在菜單中找到Qt Creator, 啓動彷佛很是快, 一秒不到就打開界面了, 徹底不像一個數百MB的程序啊sql
在網上找了一個例子, 項目名叫First, 可是編譯中出現了錯誤windows
$ gcc first.o all -o first gcc: error: all: No such file or directory
這個是由於文件名稱first引發了歧義. 將項目名改成MyFirst就正常編譯經過了.瀏覽器
The Makefile contains a generated (fake) target called "first" and it also contains a set of explicit and implied rules related to the source file "first.cpp". The make command builds your TARGET (which is named after the directory if not specified) and then decides that because "first.o" changed it must rebuild the "first" target: at this point it gets confused.
$ make /usr/bin/moc -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -I. first.cpp -o first.moc g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -I. -o first.o first.cpp g++ -Wl,-O1 -Wl,-rpath,/usr/lib/qt4 -o simple_example first.o -L/usr/lib/qt4 -lQtSql -L/usr/lib/mysql -L/usr/lib/qt4 -lQtGui -L/usr/X11R6/lib -lQtCore -lgthread-2.0 -lrt -lglib-2.0 -lpthread gcc first.o all -o first // <<<<< confused, decides to rebuild "first" target using a file called "all" gcc: all: No such file or directory make: *** [first] Error 1
You get similar confusion (that make recovers from) if "TARGET = first" even with no files called "first.cpp".
$ make /usr/bin/moc -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -I. main.cpp -o main.moc g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -I. -o main.o main.cpp make: Circular all <- first dependency dropped. // <<<< confused but recognises the situation g++ -Wl,-O1 -Wl,-rpath,/usr/lib/qt4 -o first main.o -L/usr/lib/qt4 -lQtSql -L/usr/lib/mysql -L/usr/lib/qt4 -lQtGui -L/usr/X11R6/lib -lQtCore -lgthread-2.0 -lrt -lglib-2.0 -lpthread
Adding
.PHONY = first
to Makefile fixes this problem but probably generates another if the TARGET = first. The change would be overwritten by qmake anyway. Easier to just avoid it.
F2 跳轉到變量的聲明, 切換函數的聲明和實現
F4 在頭文件和C文件之間切換
Ctrl + B 構建
Ctrl + R 運行
bogotobogo.com的這個教程不錯, 值得推薦 http://www.bogotobogo.com/Qt/Qt_tutorial_list_New.php
來源是
http://www.bogotobogo.com/Qt/Qt5_QMainWindow_QAction_ImageViewer.php
http://www.bogotobogo.com/Qt/Qt5_QMainWindow_QAction_ImageViewer_B.php
其中的主要部分代碼爲
MenuWindow.pro
#------------------------------------------------- # # Project created by QtCreator 2018-08-27T14:02:44 # #------------------------------------------------- QT += core gui QT += printsupport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = MenuWindow TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ mainwindow.cpp \ mydialog.cpp HEADERS += \ mainwindow.h \ mydialog.h FORMS += \ mainwindow.ui \ mydialog.ui
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QLabel> #include <QScrollArea> #include <QMenu> #include <QAction> #include "mydialog.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void open(); void print(); void zoomIn(); void zoomOut(); void normalSize(); void fitToWindow(); void about(); void newWindow(); private: Ui::MainWindow *ui; MyDialog *myDialog; QLabel *imageLabel; QScrollArea *scrollArea; QMenu *fileMenu; QMenu *viewMenu; QMenu *helpMenu; QAction *openAct; QAction *printAct; QAction *newWindowAct; QAction *exitAct; QAction *zoomInAct; QAction *zoomOutAct; QAction *normalSizeAct; QAction *fitToWindowAct; QAction *aboutAct; QAction *aboutQtAct; double scaleFactor; void updateActions(); void scaleImage(double factor); void adjustScrollBar(QScrollBar *scrollBar, double factor); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QtWidgets> #include <QFileDialog> #include <QMessageBox> #ifndef QT_NO_PRINTER #include <QPrintDialog> #endif MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); openAct = new QAction(tr("&Open..."), this); openAct->setShortcut(tr("Ctrl+O")); printAct = new QAction(tr("&Print..."), this); printAct->setShortcut(tr("Ctrl+P")); printAct->setEnabled(false); newWindowAct = new QAction(tr("&New Window"), this); newWindowAct->setShortcut(tr("Ctrl+N")); exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcut(tr("Ctrl+Q")); zoomInAct = new QAction(tr("Zoom &In (25%)"), this); zoomInAct->setShortcut(tr("Ctrl+=")); //(Ctrl)(+) zoomInAct->setEnabled(false); zoomOutAct = new QAction(tr("Zoom &Out (25%)"), this); zoomOutAct->setShortcut(tr("Ctrl+-")); //(Ctrl)(-) zoomOutAct->setEnabled(false); normalSizeAct = new QAction(tr("&Normal Size"), this); normalSizeAct->setShortcut(tr("Ctrl+S")); normalSizeAct->setEnabled(false); fitToWindowAct = new QAction(tr("&Fit to Window"), this); fitToWindowAct->setEnabled(false); fitToWindowAct->setCheckable(true); fitToWindowAct->setShortcut(tr("Ctrl+F")); aboutAct = new QAction(tr("&About"), this); aboutQtAct = new QAction(tr("About &Qt"), this); fileMenu = new QMenu(tr("&File"), this); fileMenu->addAction(openAct); fileMenu->addAction(printAct); fileMenu->addAction(newWindowAct); fileMenu->addSeparator(); fileMenu->addAction(exitAct); viewMenu = new QMenu(tr("&View"), this); viewMenu->addAction(zoomInAct); viewMenu->addAction(zoomOutAct); viewMenu->addAction(normalSizeAct); viewMenu->addSeparator(); viewMenu->addAction(fitToWindowAct); helpMenu = new QMenu(tr("&Help"), this); helpMenu->addAction(aboutAct); helpMenu->addAction(aboutQtAct); menuBar()->addMenu(fileMenu); menuBar()->addMenu(viewMenu); menuBar()->addMenu(helpMenu); imageLabel = new QLabel(this); imageLabel->setBackgroundRole(QPalette::Base); imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); imageLabel->setScaledContents(true); scrollArea = new QScrollArea(this); scrollArea->setBackgroundRole(QPalette::Dark); scrollArea->setWidget(imageLabel); setCentralWidget(scrollArea); setWindowTitle(tr("Image Viewer")); resize(500, 400); connect(openAct, SIGNAL(triggered()), this, SLOT(open())); connect(printAct, SIGNAL(triggered()), this, SLOT(print())); connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); connect(zoomInAct, SIGNAL(triggered()), this, SLOT(zoomIn())); connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(zoomOut())); connect(normalSizeAct, SIGNAL(triggered()), this, SLOT(normalSize())); connect(fitToWindowAct, SIGNAL(triggered()), this, SLOT(fitToWindow())); connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(newWindowAct, SIGNAL(triggered(bool)), this, SLOT(newWindow())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::open() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::currentPath()); if (!fileName.isEmpty()) { QImage image(fileName); if (image.isNull()) { QMessageBox::information(this, tr("Image Viewer"), tr("Cannot load %1.").arg(fileName)); return; } imageLabel->setPixmap(QPixmap::fromImage(image)); scaleFactor = 1.0; printAct->setEnabled(true); fitToWindowAct->setEnabled(true); updateActions(); if (!fitToWindowAct->isChecked()) imageLabel->adjustSize(); } } void MainWindow::print() { } void MainWindow::newWindow() { myDialog = new MyDialog(this); myDialog->resize(300, 200); /*myDialog->setModal(true); myDialog->exec();*/ myDialog->show(); } void MainWindow::zoomIn() { scaleImage(1.25); } void MainWindow::zoomOut() { scaleImage(0.8); } void MainWindow::normalSize() { imageLabel->adjustSize(); scaleFactor = 1.0; } void MainWindow::fitToWindow() { bool fitToWindow = fitToWindowAct->isChecked(); scrollArea->setWidgetResizable(fitToWindow); if (!fitToWindow) { normalSize(); } updateActions(); } void MainWindow::about() { QMessageBox::about(this, tr("About Image Viewer"), tr("<b>Image Viewer</b> example.")); } void MainWindow::updateActions() { zoomInAct->setEnabled(!fitToWindowAct->isChecked()); zoomOutAct->setEnabled(!fitToWindowAct->isChecked()); normalSizeAct->setEnabled(!fitToWindowAct->isChecked()); } void MainWindow::scaleImage(double factor) { Q_ASSERT(imageLabel->pixmap()); scaleFactor *= factor; imageLabel->resize(scaleFactor * imageLabel->pixmap()->size()); adjustScrollBar(scrollArea->horizontalScrollBar(), factor); adjustScrollBar(scrollArea->verticalScrollBar(), factor); zoomInAct->setEnabled(scaleFactor < 3.0); zoomOutAct->setEnabled(scaleFactor > 0.333); } void MainWindow::adjustScrollBar(QScrollBar *scrollBar, double factor) { int value = scrollBar->value(); int step = scrollBar->pageStep(); value = int(factor * value + ((factor - 1) * step/2)); scrollBar->setValue(value); }
結合Qt5中對於QScrollBar的說明, 對void MainWindow::scaleImage(double factor) 和 void MainWindow::adjustScrollBar(QScrollBar *scrollBar, double factor) 這兩個方法進行分析.
a. 這是滾動條的滑塊, 提供了快速的定位, 可是不能提供精確的定位
b. 箭頭按鈕用於精確地瀏覽定位, 對於文本編輯器, 典型的步長是一行, 而對於圖片則是20像素.
c. 翻頁控制部分, 點擊的效果等價於一次翻頁, 正常狀況下, 一個翻頁對於scrollbar的value的變化等於滑塊的長度.
每一個滾動條有一個value字段, 用於標示此滑塊距離滾動條起點的距離. 這個值必定是介於 minimum() 和 maximum() 之間. 在 minimum value和 maximum value時, 滑塊的位置分別如上圖所示. 因此要注意, 這個滾動條的長度並不是等於maximum().
由此可知, 對於前面例子中圖片放大factor倍時, 對於scrollbar.value:
1. 若是value不變, 那麼當圖片放大時, 由於maximum value增大, 故滑塊一邊縮小, 一邊位置會往起始方向收縮
2. 若是value與factor進行同等比例的放大, 那麼滑塊一邊縮小, 一邊起始邊界的位置保持不變
3. 若是value與factor進行同等比例放大的同時, 增長滑塊長度(pageStep)的收縮長度, 那麼滑塊一邊縮小, 一邊中心位置保持不變. 因此上面adjustScrollBar()方法的處理爲
value = int(factor * value + ((factor - 1) * step/2));
經常使用的Layout主要有如下幾種
而在主窗口中, 經常使用的底層佈局並不是Layout, 而是QSplitter. 這個自帶了對內部widget的自動拉伸, 以及分隔欄的鼠標拖動調整,很是方便. 能夠參考Redis Desktop Manager的佈局設計(是qml格式的, 可是能夠看出來佈局的設計) https://github.com/uglide/RedisDesktopManager/blob/0.9/src/qml/app.qml
import QtQuick 2.0 import QtQuick.Layouts 1.1 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.1 import QtQuick.Dialogs 1.2 import QtQml.Models 2.2 import QtQuick.Window 2.2 import Qt.labs.settings 1.0 import "." import "./common" import "./common/platformutils.js" as PlatformUtils import "./value-editor" import "./connections-tree" import "./console" import "./server-info" import "./bulk-operations" ApplicationWindow { id: approot visible: true objectName: "rdm_qml_root" title: "Redis Desktop Manager " + Qt.application.version width: 1100 height: 800 property double wRatio : (width * 1.0) / (Screen.width * 1.0) property double hRatio : (height * 1.0) / (Screen.height * 1.0) property var currentValueFormatter Component.onCompleted: { if (hRatio > 1 || wRatio > 1) { console.log("Ratio > 1.0. Resize main window.") width = Screen.width * 0.9 height = Screen.height * 0.8 } if (PlatformUtils.isOSXRetina(Screen)) { bottomTabView.implicitHeight = 100 } } Settings { category: "windows_settings" property alias x: approot.x property alias y: approot.y property alias width: approot.width property alias height: approot.height } SystemPalette { id: sysPalette } FontLoader { id: monospacedFont Component.onCompleted: { source = "qrc:/fonts/Inconsolata-Regular.ttf" } } QuickStartDialog { id: quickStartDialog objectName: "rdm_qml_quick_start_dialog" width: PlatformUtils.isOSX() ? 600 : approot.width * 0.8 } GlobalSettings { id: settingsDialog } ConnectionSettignsDialog { id: connectionSettingsDialog objectName: "rdm_connection_settings_dialog" onTestConnection: { if (connectionsManager.testConnectionSettings(settings)) { hideLoader() showMsg(qsTr("Successful connection to redis-server")) } else { hideLoader() showError(qsTr("Can't connect to redis-server")) } } onSaveConnection: connectionsManager.updateConnection(settings) } MessageDialog { id: notification objectName: "rdm_qml_error_dialog" visible: false modality: Qt.WindowModal icon: StandardIcon.Warning standardButtons: StandardButton.Ok function showError(msg) { icon = StandardIcon.Warning text = msg open() } function showMsg(msg) { icon = StandardIcon.Information text = msg open() } } BulkOperationsDialog { id: bulkOperationDialog } Connections { target: bulkOperations onOpenDialog: { bulkOperationDialog.operationName = operationName bulkOperationDialog.open() } } Connections { target: connectionsManager onEditConnection: { connectionSettingsDialog.settings = config connectionSettingsDialog.open() } onError: { notification.showError(err) } Component.onCompleted: { if (connectionsManager.size() == 0) quickStartDialog.open() } } toolBar: AppToolBar {} BetterSplitView { anchors.fill: parent orientation: Qt.Horizontal BetterTreeView { id: connectionsTree Layout.fillHeight: true Layout.minimumWidth: 350 Layout.minimumHeight: 500 } BetterSplitView { orientation: Qt.Vertical BetterTabView { id: tabs objectName: "rdm_qml_tabs" currentIndex: 0 Layout.fillHeight: true Layout.fillWidth: true Layout.minimumWidth: 650 Layout.minimumHeight: 30 onCurrentIndexChanged: { if (tabs.getTab(currentIndex).tabType) { if (tabs.getTab(currentIndex).tabType == "value") { var realIndex = currentIndex - serverStatsModel.tabsCount(); if (welcomeTab) { realIndex -= 1 } viewModel.setCurrentTab(realIndex); } else if (tabs.getTab(currentIndex).tabType == "server_info") { var realIndex = currentIndex; if (welcomeTab) { realIndex -= 1 } serverStatsModel.setCurrentTab(index); } } } WelcomeTab { id: welcomeTab clip: true objectName: "rdm_qml_welcome_tab" property bool not_mapped: true onClose: tabs.removeTab(index) function closeIfOpened() { var welcomeTab = tabs.getTab(0) if (welcomeTab && welcomeTab.not_mapped) tabs.removeTab(0) } } ServerInfoTabs { model: serverStatsModel } Connections { target: serverStatsModel onRowsInserted: if (welcomeTab) welcomeTab.closeIfOpened() } ValueTabs { objectName: "rdm_qml_value_tabs" model: valuesModel } AddKeyDialog { id: addNewKeyDialog objectName: "rdm_qml_new_key_dialog" width: approot.width * 0.7 height: { if (approot.height > 500) { return approot.height * 0.7 } else { return approot.height } } } Connections { target: valuesModel onKeyError: { if (index != -1) tabs.currentIndex = index notification.showError(error) } onRowsInserted: { if (welcomeTab) welcomeTab.closeIfOpened() } onNewKeyDialog: addNewKeyDialog.open() } } BetterTabView { id: bottomTabView Layout.fillWidth: true Layout.minimumHeight: PlatformUtils.isOSXRetina()? 15 : 30 tabPosition: Qt.BottomEdge Consoles { objectName: "rdm_qml_console_tabs" model: consoleModel } Connections { target: consoleModel onChangeCurrentTab: { bottomTabView.currentIndex = i + 1 } } BetterTab { closable: false title: "Log" icon: "qrc:/images/log.svg" BaseConsole { id: logTab readOnly: true textColor: "#6D6D6E" Connections { target: appLogger onEvent: logTab.append(msg) Component.onCompleted: appLogger.getMessages() } } } } } } }
1. 設計好全局的QAction, 這個能夠被頂欄菜單QMenuBar, 工具欄QToolBar 以及 右鍵彈出菜單QMenu引用.
2. 設計好主窗體佈局和主要widget
3. 開始製做各類slot, 而且將QAction connect到對應的slot上, 這一步須要開始設計各個彈出的QDialog
一個未完成的主窗口例子
rockredismain.h
#ifndef ROCKREDISMAIN_H #define ROCKREDISMAIN_H #include <QMainWindow> #include <QSplitter> #include <QTreeWidget> #include <QTableWidget> #include <QMenuBar> #include <QMenu> #include <QAction> #include <QToolBar> #include <QLabel> #include <QScrollArea> #include <QVBoxLayout> namespace Ui { class RockRedisMain; } class RockRedisMain : public QMainWindow { Q_OBJECT public: explicit RockRedisMain(QWidget *parent = 0); ~RockRedisMain(); private slots: void onCustomContextMenuRequested(const QPoint& point); void showContextMenu(QTreeWidgetItem* item, const QPoint& globalPos); void onCurrentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); private: Ui::RockRedisMain *ui; QSplitter * splitter; QScrollArea *scrollArea; QTreeWidget *treeWidget; QTableWidget* tableWidget; QMenu *fileMenu; QMenu *helpMenu; QToolBar *fileToolBar; QAction *newConnectionAct; QAction *editConnectionAct; QAction *removeConnectionAct; QAction *exitAct; QAction *aboutAct; void initMenu(); QTreeWidgetItem* addTreeNode(QString name, QString description); QTreeWidgetItem* addChildNode(QTreeWidgetItem *parent, QString name, QString description); }; #endif // ROCKREDISMAIN_H
rockredismain.cpp
#include "rockredismain.h" #include "ui_rockredismain.h" RockRedisMain::RockRedisMain(QWidget *parent) : QMainWindow(parent), ui(new Ui::RockRedisMain) { ui->setupUi(this); initMenu(); splitter = new QSplitter(Qt::Horizontal, this); setCentralWidget(splitter); treeWidget = new QTreeWidget(); treeWidget->setHeaderHidden(true); //treeWidget->setHeaderLabels(QStringList() << "Connections"); treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); QTreeWidgetItem* item = addTreeNode("Folder", "It's a folder"); addChildNode(item, "A Connection Folder", "first"); addChildNode(item, "B Connection File", "second"); item = addTreeNode("File", "it's a file"); addChildNode(item, "A", "first"); addChildNode(item, "B", "second"); addTreeNode("Folder", "It's a folder"); addTreeNode("File", "it's a file"); addTreeNode("Folder", "It's a folder"); addTreeNode("File", "it's a file"); addTreeNode("Folder", "It's a folder"); addTreeNode("File", "it's a file"); treeWidget->resize(100, 100); splitter->addWidget(treeWidget); tableWidget = new QTableWidget(); splitter->addWidget(tableWidget); splitter->setStretchFactor(1,1); setWindowTitle(tr("RockRedis")); resize(800, 600); connect(treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint))); connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(onCurrentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); } RockRedisMain::~RockRedisMain() { delete ui; } void RockRedisMain::initMenu() { fileMenu = new QMenu(tr("&File"), this); helpMenu = new QMenu(tr("&Help"), this); menuBar()->addMenu(fileMenu); menuBar()->addMenu(helpMenu); newConnectionAct = new QAction(tr("&New Connection"), this); newConnectionAct->setShortcut(tr("Ctrl+N")); newConnectionAct->setStatusTip(tr("Add a new connection")); //connect(newConnectionAct, SIGNAL(triggered()), this, SLOT(open())); fileMenu->addAction(newConnectionAct); editConnectionAct = new QAction(tr("&Edit Connection"), this); editConnectionAct->setShortcut(tr("Alt+E")); editConnectionAct->setEnabled(false); //connect(editConnectionAct, SIGNAL(triggered()), this, SLOT(print())); fileMenu->addAction(editConnectionAct); removeConnectionAct = new QAction(tr("Remove Connection"), this); editConnectionAct->setShortcut(tr("Del")); removeConnectionAct->setEnabled(false); //connect(newWindowAct, SIGNAL(triggered(bool)), this, SLOT(newWindow())); fileMenu->addAction(removeConnectionAct); exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcut(tr("Ctrl+Q")); connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); fileMenu->addAction(exitAct); aboutAct = new QAction(tr("&About"), this); helpMenu->addAction(aboutAct); } QTreeWidgetItem* RockRedisMain::addTreeNode(QString name, QString description) { QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget, 0); item->setText(0, name); item->setText(1, description); return item; } QTreeWidgetItem* RockRedisMain::addChildNode(QTreeWidgetItem *parent, QString name, QString description) { QTreeWidgetItem *item = new QTreeWidgetItem(parent, 1); item->setText(0, name); item->setText(1, description); return item; } void RockRedisMain::onCustomContextMenuRequested(const QPoint& point) { QTreeWidgetItem* item = treeWidget->itemAt(point); if (item) { // Note: We must map the point to global from the viewport to // account for the header. showContextMenu(item, treeWidget->mapToGlobal(point)); } } void RockRedisMain::showContextMenu(QTreeWidgetItem* item, const QPoint& point) { QMenu menu; switch (item->type()) { case 0: menu.addAction(editConnectionAct); menu.addAction(removeConnectionAct); break; case 1: menu.addAction("This is a type 2"); break; } menu.exec(point); } void RockRedisMain::onCurrentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { if (current == NULL) { editConnectionAct->setEnabled(false); removeConnectionAct->setEnabled(false); } else if (current->type() == 0) { editConnectionAct->setEnabled(true); removeConnectionAct->setEnabled(true); } else { editConnectionAct->setEnabled(false); removeConnectionAct->setEnabled(false); } }