質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

1回答

2406閲覧

QTアプリケーションでのUndo/Redo

退会済みユーザー

退会済みユーザー

総合スコア0

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/02/27 11:43

前提・実現したいこと

QTアプリケーション上でUndo/Redoの機能を実装するためにQUndoStack,QUndoCommandクラスを使用し練習を行っています。

試しにChangeボタンを押した際にSpinBoxの数値の値をlineEditに反映するといったアプリケーションを作成し、Undoボタンを押下した際に前の値に戻りRedoボタンを押下した際には後の値に戻るといったプログラムを作成したのですが、私が作成したアプリケーションではUndo/Redoボタンを2回押下しないと値の変更がされないといった不具合が発生しています。

イメージ説明
①のスピンボックスで値を変更し③のChangeボタンを押下した際に②のlineEditのスピンボックスで選択した値が変更されるといったプログラムとなっております。
図の状態でUndoボタンを1度押下した際に4の値がlineEditに判明されてほしいのですが、2回押下しないと反映されずRedoする際にも2回押下しないと反映されないといった問題が発生しています。

どうにかして、1回のボタン押下で反映されるように修正したいのですがどうすれば良いのでしょうか。
ご指南頂けると幸甚に存じます。

該当のソースコード

C++

1[main.cpp] 2#include "widget.h" 3#include <QApplication> 4 5#include <QUndoStack> 6int main(int argc, char *argv[]) 7{ 8 QApplication a(argc, argv); 9 QUndoStack *m_undoStack = new QUndoStack; 10 Widget w(m_undoStack); 11 w.show(); 12 13 return a.exec(); 14}

C++

1[Widget.h] 2#ifndef WIDGET_H 3#define WIDGET_H 4 5#include <QWidget> 6#include <QUndoStack> 7#include <QUndoView> 8 9namespace Ui { 10class Widget; 11} 12 13class Widget : public QWidget 14{ 15 Q_OBJECT 16 17public: 18 explicit Widget(QUndoStack *undoStack,QWidget *parent = 0); 19 ~Widget(); 20 21protected: 22 void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE; 23 24public: 25 void onChangeButtonClicked(); 26 void changeDisplay(int value); 27 28public slots: 29 void changeValueSpinBox(int value); 30 31private: 32 Ui::Widget *ui; 33 QUndoStack *m_undoStack; 34 QUndoView *m_undoView; 35 int m_value; 36 QList<int> m_valueList; 37 38}; 39 40#endif // WIDGET_H

C++

1[Widget.cpp] 2#include "widget.h" 3#include "ui_widget.h" 4#include "command.h" 5 6Widget::Widget(QUndoStack *undoStack,QWidget *parent) : 7 QWidget(parent), 8 ui(new Ui::Widget), 9 m_undoStack(undoStack), 10 m_undoView(new QUndoView(m_undoStack)) 11{ 12 ui->setupUi(this); 13 connect(ui->undoButton,&QPushButton::clicked,m_undoStack,&QUndoStack::undo); 14 connect(ui->redoButton,&QPushButton::clicked,m_undoStack,&QUndoStack::redo); 15 connect(ui->changeButton,&QPushButton::clicked,this,&Widget::onChangeButtonClicked); 16 connect(ui->spinBox,SIGNAL(valueChanged(int)),this,SLOT(changeValueSpinBox(int))); 17 18 m_undoView->setWindowFlags(Qt::Dialog); 19 m_undoView->show(); 20 21} 22 23Widget::~Widget() 24{ 25 delete ui; 26} 27 28void Widget::closeEvent(QCloseEvent *) 29{ 30 m_undoView->close(); 31} 32 33void Widget::onChangeButtonClicked() 34{ 35 qInfo("Click"); 36 command *Command = new command(this,m_value,&m_valueList); 37 m_undoStack->push(Command); 38} 39 40void Widget::changeValueSpinBox(int value) 41{ 42 qInfo("Value Change"); 43 m_value = value; 44} 45 46void Widget::changeDisplay(int value) 47{ 48 ui->lineEdit->setText(QString::number(value)); 49}

C++

1[command.h] 2#ifndef COMMAND_H 3#define COMMAND_H 4 5#include <QUndoCommand> 6 7class Widget; 8 9class command : public QUndoCommand 10{ 11public: 12 command(Widget *widget,const int value,QList<int> *valueList,QUndoCommand *parent = 0); 13 14 15public: 16 void undo() Q_DECL_OVERRIDE; 17 void redo() Q_DECL_OVERRIDE; 18 19private: 20 Widget *m_widget; 21 int m_value; 22 QList<int> *m_valueList; 23}; 24 25#endif // COMMAND_H

C++

1[command.cpp] 2#include "command.h" 3#include "widget.h" 4 5command::command(Widget *widget,const int value,QList<int> *valueList,QUndoCommand *parent): 6 QUndoCommand(parent), 7 m_widget(widget), 8 m_value(value), 9 m_valueList(valueList) 10{ 11} 12 13void command::undo() 14{ 15 qInfo("UNDO"); 16 if(m_valueList->isEmpty()) 17 { 18 return; 19 } 20 21 m_widget->changeDisplay(m_valueList->takeLast()); 22} 23 24void command::redo() 25{ 26 qInfo("REDO"); 27 m_valueList->push_back(m_value); 28 setText(QString("Value:%1").arg(m_value)); 29 m_widget->changeDisplay(m_value); 30}
[widget.ui] <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Widget</class> <widget class="QWidget" name="Widget"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>400</width> <height>300</height> </rect> </property> <property name="windowTitle"> <string>Widget</string> </property> <widget class="QPushButton" name="redoButton"> <property name="geometry"> <rect> <x>220</x> <y>120</y> <width>158</width> <height>32</height> </rect> </property> <property name="text"> <string>Redo</string> </property> </widget> <widget class="QPushButton" name="undoButton"> <property name="geometry"> <rect> <x>220</x> <y>60</y> <width>158</width> <height>32</height> </rect> </property> <property name="text"> <string>Undo</string> </property> </widget> <widget class="QLineEdit" name="lineEdit"> <property name="geometry"> <rect> <x>30</x> <y>140</y> <width>113</width> <height>21</height> </rect> </property> </widget> <widget class="QSpinBox" name="spinBox"> <property name="geometry"> <rect> <x>70</x> <y>70</y> <width>48</width> <height>24</height> </rect> </property> </widget> <widget class="QPushButton" name="changeButton"> <property name="geometry"> <rect> <x>230</x> <y>180</y> <width>113</width> <height>32</height> </rect> </property> <property name="text"> <string>Change</string> </property> </widget> </widget> <layoutdefault spacing="6" margin="11"/> <resources/> <connections/> </ui>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

公式のドキュメントやサンプルを良く読んで実装をしましょう。
https://doc.qt.io/qt-5/qundo.html
https://doc.qt.io/qt-5/qundocommand.html
https://doc.qt.io/qt-5/qtwidgets-tools-undoframework-example.html

シンプルにやりたいことを実現しようとすると以下のようなコードになるのではないでしょうか。

cpp

1// widget.h 2#ifndef WIDGET_H 3#define WIDGET_H 4 5#include <QWidget> 6#include <QUndoStack> 7#include <QUndoView> 8 9namespace Ui { 10class Widget; 11} 12 13class Widget : public QWidget 14{ 15 Q_OBJECT 16 17public: 18 explicit Widget(QUndoStack *undoStack,QWidget *parent = 0); 19 ~Widget(); 20 21protected: 22 void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE; 23 24private slots: 25 void onChangeButtonClicked(); 26 27private: 28 Ui::Widget *ui; 29 QUndoStack *m_undoStack; 30 QUndoView *m_undoView; 31}; 32 33#endif // WIDGET_H

cpp

1// widget.cpp 2#include "widget.h" 3#include "ui_widget.h" 4#include "command.h" 5 6Widget::Widget(QUndoStack *undoStack,QWidget *parent) : 7 QWidget(parent), 8 ui(new Ui::Widget), 9 m_undoStack(undoStack), 10 m_undoView(new QUndoView(m_undoStack)) 11{ 12 ui->setupUi(this); 13 connect(ui->undoButton,&QPushButton::clicked,m_undoStack,&QUndoStack::undo); 14 connect(ui->redoButton,&QPushButton::clicked,m_undoStack,&QUndoStack::redo); 15 connect(ui->changeButton,&QPushButton::clicked,this,&Widget::onChangeButtonClicked); 16 17 m_undoView->setWindowFlags(Qt::Dialog); 18 m_undoView->show(); 19 20} 21 22Widget::~Widget() 23{ 24 delete ui; 25} 26 27void Widget::closeEvent(QCloseEvent *) 28{ 29 m_undoView->close(); 30} 31 32void Widget::onChangeButtonClicked() 33{ 34 qInfo("Click"); 35 command *Command = new command(ui->lineEdit, ui->spinBox->value()); 36 m_undoStack->push(Command); 37}

cpp

1// command.h 2#ifndef COMMAND_H 3#define COMMAND_H 4 5#include <QUndoCommand> 6 7class QLineEdit; 8 9class command : public QUndoCommand 10{ 11public: 12 command(QLineEdit *lineEdit, const int value, QUndoCommand *parent = 0); 13 14 15public: 16 void undo() Q_DECL_OVERRIDE; 17 void redo() Q_DECL_OVERRIDE; 18 19private: 20 QLineEdit *lineEdit; 21 QString from; 22 QString to; 23}; 24 25#endif // COMMAND_H

cpp

1// command.cpp 2#include "command.h" 3#include <QLineEdit> 4 5command::command(QLineEdit *lineEdit,const int value,QUndoCommand *parent): 6 QUndoCommand(parent), 7 lineEdit(lineEdit), 8 from(lineEdit->text()), 9 to(QString::number(value)) 10{ 11 setText(QString("%1->%2").arg(from).arg(to)); 12} 13 14void command::undo() 15{ 16 qInfo("UNDO"); 17 lineEdit->setText(from); 18} 19 20void command::redo() 21{ 22 qInfo("REDO"); 23 lineEdit->setText(to); 24}

投稿2020/02/27 13:43

tasuku.

総合スコア347

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問