Продолжаем работать с интерфейсом нашего проекта (начало тут) и сегодня создадим меню для работы непосредственно с графиком. В качестве примера добавим пункт меню Graph и подпункт Scale для изменения пределов по осям x и y.
Сначала создадим диалоговое окно, содержащее два объекта класса QSpinBox. В этом окне пользователь выберет максимальные значения для отображения на осях. Для всего этого мы реализуем новый класс ScaleActionMenu. Итак, идем в файл menuclass.h и добавляем туда объявление нашего класса:
class ScaleActionMenu : public QWidget { Q_OBJECT public: explicit ScaleActionMenu(QWidget *parent = 0); QSpinBox *xAxisMaxSpinBox; QSpinBox *yAxisMaxSpinBox; private: QLabel *xAxisLabel; QLabel *xAxisMaxLabel; QLabel *yAxisLabel; QLabel *yAxisMaxLabel; signals: void valueChanged(int i); };
Объекты QLabel нам нужны для создания надписей в меню, к примеру "Axis X". Для общения же с пользователем, как и решили выше, будем использовать spinbox’ы:
QSpinBox *xAxisMaxSpinBox; QSpinBox *yAxisMaxSpinBox;
Кроме этого объявляем сигнал valueChanged(int i), который нужен, собственно, для того, чтобы обработать выбор пользователя. Скоро мы привяжем к этому сигналу парочку слотов, но сначала закончим с диалоговым окном – создадим конструктор класса в файле menuclass.cpp:
ScaleActionMenu::ScaleActionMenu(QWidget *parent) : QWidget(parent) { this->setWindowTitle("Scale"); xAxisLabel = new QLabel("X Axis Scale"); xAxisMaxLabel = new QLabel("Maximum Value"); yAxisLabel = new QLabel("Y Axis Scale"); yAxisMaxLabel = new QLabel("Maximum Value"); xAxisMaxSpinBox = new QSpinBox; yAxisMaxSpinBox = new QSpinBox; xAxisMaxSpinBox->setRange(0,10); yAxisMaxSpinBox->setRange(0,10); QVBoxLayout *scaleActionMenuLayout = new QVBoxLayout; scaleActionMenuLayout->addWidget(xAxisLabel); scaleActionMenuLayout->addWidget(xAxisMaxLabel); scaleActionMenuLayout->addWidget(xAxisMaxSpinBox); scaleActionMenuLayout->addWidget(yAxisLabel); scaleActionMenuLayout->addWidget(yAxisMaxLabel); scaleActionMenuLayout->addWidget(yAxisMaxSpinBox); this->setLayout(scaleActionMenuLayout); this->resize(150, 200); }
Давайте опять прямо по строчкам разбираться, что тут происходит. Задаем имя окна, а также текст, который поможет пользователю понять, что же вообще от него требуется:
this->setWindowTitle("Scale"); xAxisLabel = new QLabel("X Axis Scale"); xAxisMaxLabel = new QLabel("Maximum Value"); yAxisLabel = new QLabel("Y Axis Scale"); yAxisMaxLabel = new QLabel("Maxomum Value");
Все эти объекты QLabel – просто текст и ничего более. Когда будет создано окно, можно будет увидеть, что и где отображается. Теперь создаем "спинбоксы" и задаем пределы, в которых могут меняться значения:
xAxisMaxSpinBox = new QSpinBox; yAxisMaxSpinBox = new QSpinBox; xAxisMaxSpinBox->setRange(0,10); yAxisMaxSpinBox->setRange(0,10);
То есть значение xAxisMaxSpinBox может меняться от 0 до 10, соответственно на оси x будут отображаться разные значения. Забегая вперед, скажу, что по оси y мы будем менять только максимальное отображаемое значение, а по оси x – и минимальное и максимальное. Например, при значении xAxisMaxSpinBox, равном 5, на оси x будут значения от -5 до 5, а при значении yAxisMaxSpinBox (отвечает за ось y), равном 5, на оси y будут значения от 0 до 5. Это связано с тем что у нас функция симметричная относительно оси y.
Так... Продолжаем, дальше мы просто располагаем все элементы друг над другом в нужной нам последовательности:
QVBoxLayout *scaleActionMenuLayout = new QVBoxLayout; scaleActionMenuLayout->addWidget(xAxisLabel); scaleActionMenuLayout->addWidget(xAxisMaxLabel); scaleActionMenuLayout->addWidget(xAxisMaxSpinBox); scaleActionMenuLayout->addWidget(yAxisLabel); scaleActionMenuLayout->addWidget(yAxisMaxLabel); scaleActionMenuLayout->addWidget(yAxisMaxSpinBox); this->setLayout(scaleActionMenuLayout); this->resize(150, 200);
И меняем размер окна. Теперь нам нужно создать пункт верхнего меню Graph и в выпадающем меню – пункт Scale. Для этого делаем все также, как в первой части этого повествования (в начале статьи есть ссылочка). Объявляем слоты:
void showScaleMenu(); void scaleActionX(int i); void scaleActionY(int i);
Первый слот – для показа диалогового окна при выборе меню Scale, два других слота – для изменения пределов по осям x и y соответственно. Помимо этого в файле MainWindow.h добавляем еще пару членов к классу:
QMenu *graphMenu; QAction *saveAction;
И переходим к файлу MainWindow.cpp. В методе createActions() добавляем:
scaleAction = new QAction(tr("&Scale"), this); connect(scaleAction, SIGNAL(activated()), this, SLOT(showScaleMenu()));
Здесь мы привязали к пункту меню слот showScaleMenu(). Сразу же, пока не забыли, в методе createMenu() дописываем:
graphMenu = menuBar()->addMenu(tr("&Graph")); graphMenu->addAction(scaleAction);
Подготовка завершена, реализуем слот showScaleMenu():
void MainWindow::showScaleMenu() { ScaleActionMenu *scaleMenu = new ScaleActionMenu(); scaleMenu->setVisible(true); connect(scaleMenu->xAxisMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(scaleActionX(int))); connect(scaleMenu->yAxisMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(scaleActionY(int))); }
Здесь мы создаем объект нашего класса ScaleActionMenu и показываем его пользователю. А к QSpinBox (точнее к сигналам, который они эмитируют при изменении значения) прикручиваем слоты scaleActionX(int) и scaleActionY(int).
Осталось совсем немного, пишем методы, которые выполнят полезную работу :
void MainWindow::scaleActionX(int i) { this->plot->setAxisScale(QwtPlot::xBottom, -i, i); plot->replot(); } void MainWindow::scaleActionY(int i) { this->plot->setAxisScale(QwtPlot::yLeft, 0, i); plot->replot(); }
Тут все вроде бы очевидно, так что пробуем запустить:
Получили то, что хотели, все работает верно )
В общем ничего сложного тут нет, но, разобравшись с таким меню, можно в принципе написать довольно удобный интерфейс для любого своего приложения.