Error while trying Undo Redo - c++

I am trying to do undo/redo on multidocument interface but facing following error:
no matching function for call to 'qobject_cast(QMdiSubWindow*&)'
return qobject_cast<CadGraphicsView *>(activeSubWindow);
My code to above function is as follows:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
m_undoGroup = new QUndoGroup(this);
QAction *undoAction = m_undoGroup->createUndoAction(this);
undoAction->setShortcut(QKeySequence::Undo);
QAction *redoAction = m_undoGroup->createRedoAction(this);
redoAction->setShortcut(QKeySequence::Redo);
menuEdit->insertAction(menuEdit->actions().at(0), undoAction);
menuEdit->insertAction(undoAction, redoAction);
menuEdit->addAction(undoAction);
menuEdit->addAction(redoAction);
updateActions();
}
void MainWindow::setCurrentDocument()
{
mdiArea->currentSubWindow();
}
void MainWindow::addnewFile()
{
m_undoGroup->addStack(view->scene->undoStack());
connect(view->scene->undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
connect(view->scene->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));
}
void MainWindow::updateActions()
{
CadGraphicsScene *scene = currentDocument();
m_undoGroup->setActiveStack(scene == 0 ? 0 : scene->undoStack());
}
CadGraphicsView *MainWindow::currentDocument() const
{
if (QMdiSubWindow *activeSubWindow = mdiArea->currentSubWindow())
return qobject_cast<CadGraphicsView *>(activeSubWindow);
return 0;
}
void MainWindow::newFile()
{
// creates a new file
createMdiView();
view->newFile();
addnewFile();
curFileName = tr("Document %1").arg(++fileNumber);
view->setWindowTitle(curFileName);
view->scene->installEventFilter(this);
view->show();
isEntitySelected = false;
}
CadGraphicsView *MainWindow::createMdiView()
{
// creates a graphicsView and add it to the MDI window
view = new CadGraphicsView;
QMdiSubWindow *w = mdiArea->addSubWindow(view);
mdiArea->setActiveSubWindow(w);
windowViewList.append(qMakePair(w, view));
return view;
}
Can you please help me to solve the error. I have added the basic idea how it is working.

Got the solution to my problem. I need to change the currentDocument function as follows:
CadGraphicsView *MainWindow::currentDocument() const
{
return qobject_cast<CadGraphicsView *>(mdiArea->parentWidget());
}

Related

Style Sheet ignored on class inherited from QWidget [duplicate]

I have several custom widget in my current project. I wish to apply stylesheets to them and when I do so inside Qt Creator, it appears to work. However, when executing the program, no stylesheet is used. The stylesheets for the Qt widgets are working normally.
Does anyone have any advice?
WidgetUnits.h
#ifndef WIDGETUNITS_H
#define WIDGETUNITS_H
#include <QList>
#include <QWidget>
#include <QPainter>
#include <Widgets/JECButton.h>
#include <Unit.h>
#include <Time.h>
namespace Ui
{
class WidgetUnits;
}
class WidgetUnits : public QWidget
{
Q_OBJECT
public:
explicit WidgetUnits(QWidget *parent = 0);
~WidgetUnits();
void setNumTimes(const int& numTimes);
public slots:
void updatePictures(const Time* time);
protected:
void paintEvent(QPaintEvent *event);
private:
void checkNewQueue(const QList<QList<Unit*>*>* units);
Ui::WidgetUnits *ui;
const int pictureWidth; // The width of the Unit pictures.
const int pictureHeight; // The height of the Unit pictures.
QList<QList<JECButton*>*> buttonPictures; // The Units' pictures. The outer QList stores the QList of pictures for a given tick.
// The inner QList stores the JECButtons for the specific tick.
};
WidgetUnits.cpp
#include "WidgetUnits.h"
#include "ui_WidgetUnits.h"
WidgetUnits::WidgetUnits(QWidget *parent):
QWidget(parent),
ui(new Ui::WidgetUnits),
pictureWidth(36),
pictureHeight(36)
{
ui->setupUi(this);
}
WidgetUnits::~WidgetUnits()
{
delete ui;
}
void WidgetUnits::updatePictures(const Time *time)
{
// Only showing units that started to get built this turn.
checkNewQueue(time->getUnits());
checkNewQueue(time->getBuildings());
checkNewQueue(time->getUpgrades());
// Updating the position of the remaining pictures (after some were removed).
// Checking the maximum number of Units made in one tick.
int maxNewQueue = 0;
for (int a = 0; a < buttonPictures.length(); ++a)
{
if (buttonPictures.at(a)->length() > maxNewQueue)
{
maxNewQueue = buttonPictures.at(a)->length();
}
}
if (buttonPictures.length() > 0)
{
this->setGeometry(0, 0, buttonPictures.length() * 130,
maxNewQueue * (pictureWidth + 10) + 20);
QList<JECButton*>* tickButtons = 0;
for (int a = 0; a < buttonPictures.length(); ++a)
{
tickButtons = buttonPictures.at(a);
for (int b = 0; b < tickButtons->length(); ++b)
{
tickButtons->at(b)->move(a * 130, b * (pictureHeight + 10));
}
}
}
update();
}
void WidgetUnits::checkNewQueue(const QList<QList<Unit *> *> *units)
{
if (units != 0)
{
const Unit* currentUnit = 0;
JECButton* currentButton = 0;
for (int a = 0; a < units->length(); ++a)
{
buttonPictures.append(new QList<JECButton*>());
for (int b = 0; b < units->at(a)->length(); ++b)
{
currentUnit = units->at(a)->at(b);
// Verifying that there is an item in the queue and the queue action was started this turn.
if (currentUnit->getQueue() != 0 && currentUnit->getAction()->getTimeStart() == currentUnit->getAction()->getTimeCurrent()
&& (currentUnit->getAction()->getType() == Action::BUILD || currentUnit->getAction()->getType() == Action::TRAIN ||
currentUnit->getAction()->getType() == Action::UPGRADE))
{
buttonPictures.last()->append(new JECButton(this));
currentButton = buttonPictures.last()->last();
QImage* image = new QImage(currentUnit->getQueue()->getUnitBase()->getImage().scaled(pictureWidth, pictureHeight));
currentButton->setImage(*image);
currentButton->setGeometry(0, 0, currentButton->getImage().width(),
currentButton->getImage().height());
currentButton->setColorHover(QColor(0, 0, 225));
currentButton->setColorPressed(QColor(120, 120, 120));
currentButton->setImageOwner(true);
currentButton->setVisible(true);
}
}
}
}
}
void WidgetUnits::setNumTimes(const int &numTimes)
{
// Appending new button lists for added ticks.
for (int a = buttonPictures.length(); a < numTimes; ++a)
{
buttonPictures.append(new QList<JECButton*>());
}
}
void WidgetUnits::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
}
The widget is visible- I set a tooltip which it showed me (It's just the same color of the QScrollArea it's sitting in).
I had a similar problem and it was solved using jecjackal's comment. As sjwarner said, it would be much more noticeable in the form of an answer. So I'll provide it. For the benefit of any future viewers. Again, it isn't my answer! Appreciate jecjackal for it!
As it is said in the Qt's stylesheets reference, applying CSS styles to custom widgets inherited from QWidget requires reimplementing paintEvent() in that way:
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
Without doing it your custom widgets will support only the background, background-clip and background-origin properties.
You can read about it here: Qt Stylesheets reference in the section "List of Stylable Widgets" -> QWidget.
There is an answer much easier than writing your own paintEvent: subclass QFrame instead of QWidget and it will work right away:
class WidgetUnits : public QFrame
{
Q_OBJECT
....
For completeness, the same problem is present in PyQt. You can apply a stylesheet to a subclassed QWidget by adding similar code:
def paintEvent(self, pe):
opt = QtGui.QStyleOption()
opt.init(self)
p = QtGui.QPainter(self)
s = self.style()
s.drawPrimitive(QtGui.QStyle.PE_Widget, opt, p, self)
I had same problem with pyside. I post my solution just for completeness.
It is almost like in PyQt as Pieter-Jan Busschaert proposed.
only difference is you need to call initFrom instead of init
def paintEvent(self, evt):
super(FreeDockWidget,self).paintEvent(evt)
opt = QtGui.QStyleOption()
opt.initFrom(self)
p = QtGui.QPainter(self)
s = self.style()
s.drawPrimitive(QtGui.QStyle.PE_Widget, opt, p, self)
One other thing you need to make sure is that you define your custom widget in your css file the following way:
FreeDockWidget{...}
and not like often recommended
QDockWidget#FreeDockWidget{...}
Calling setAttribute(Qt::WA_StyledBackground, true) for the custom widget worked for me.
Setting Qt::WA_StyledBackground to true only works if you remember to add Q_OBJECT to your class. With these two changes you don't need to reimplement paintEvent.

SQL Parameter count mismatch on QTableView

I have a GUI composed of:
N.1 GraphicsView
N.1 QTableView
N.1 dialog that opens up as needed by the user after doubleclicking on each row of the QTableView
I can capture features on the QGraphicsView with the mouse click. After the feature is drawn I right click and open up a dialog like the one in the figure:
After hitting accept: I register the feature as the row index of the QTableView as shown below:
If I doubleclick on each row I am able to open again the same dialog with the information previously saved. I do that because I may need to change the name of the image and call it differently.
The problem I currently have is that I ma receiving a weird Parameter count mismatch from the compiler and I don't understand why and it should be due to QSQLITE
Below is what I am trying to do along with the most important part of the code:
parameters.h
typedef struct Param
{
int mId;
QString mName;
QByteArray mSave;
} Param;
class Parameters
{
public:
Parameters() = default;
Parameters(Param newdata);
Parameters(int id, const QString &name, const QByteArray &save);
int id() const { return data.mId; }
QString name() const {return data.mName; }
QByteArray save() const {return data.mSave; }
Param getData() const { return data; }
void setData(Param ndat) { data = ndat; }
private:
Param data;
};
parameters.cpp
#include "parameters.h"
Parameters::Parameters(Param newdata) {
data = newdata;
}
Parameters::Parameters(int id, const QString &name,
const QByteArray &save) {
data.mId = id;
data.mSave = save;
data.mName = name;
}
the database is set in the following dataleftcamera.h part:
public:
explicit dataLeftCamera(QObject *parent = nullptr);
bool addItem(Parameters* mParameters);
bool updateItem(int itemId, Parameters* mParameters);
QSqlDatabase getDatabase();
private:
QString mError;
QSqlDatabase mDatabaseLeft;
The table is initiated here on dataleftcamera.cpp and here is where the compiler is giving the Parameter count mismatch error specifically on the function updateItem
#define CREATE_TABLE \
" CREATE TABLE IF NOT EXISTS leftCamTable" \
" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" \
", name TEXT NOT NULL" \
", save BLOB NOT NULL)"
dataLeftCamera::dataLeftCamera(QObject *parent) : QObject (parent)
{}
bool dataLeftCamera::addItem(Parameters *mParameters)
{
QSqlQuery qry;
qry.prepare("INSERT INTO leftCamTable (name, save)"\
" VALUES (?,?)");
qry.addBindValue(mParameters->name());
qry.addBindValue(mParameters->save());
bool ok = qry.exec();
if(!ok) {
mError = qry.lastError().text();
qDebug() << mError;
}
}
bool dataLeftCamera::updateItem(int itemId, Parameters *mParameters)
{
QSqlQuery qry;
qry.prepare(" UPDATE lefCamTable SET " \
" name = ?," \
" save = ?" \
" WHERE id = ?");
qry.addBindValue(mParameters->name());
qry.addBindValue(mParameters->save());
qry.addBindValue(itemId);
bool ok = qry.exec();
if(!ok) {
mError = qry.lastError().text();
qDebug() << mError;
}
}
On the mainwindow.cpp is the part where I update the item after I doubleclick on the row to change the name of the image and accept again the modification:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mDatabaseLeftCamera = new dataLeftCamera(this);
mModelLeftCamera = nullptr;
mModelLeftCamera = new QSqlTableModel(this);
ui->tableView->setModel(mModelLeftCamera);
connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)),
this, SLOT(onTableClick(QModelIndex)));
// temporary folder
temporaryFolder = "/home/name/Desktop/tempDBFolder/tmp.db";
QFile dbRem(temporaryFolder);
dbRem.remove();
mDatabaseLeftCamera->inizializationDatabaseLeftCamera(temporaryFolder);
mDatabaseLeftCamera->configurationDatabaseLeftCamera();
mModelLeftCamera = new QSqlTableModel(this, mDatabaseLeftCamera->getDatabase());
mModelLeftCamera->setTable("leftCamTable");
mModelLeftCamera->select();
ui->tableView->setModel(mModelLeftCamera);
ui->tableView->showColumn(true);
}
// opening the dialog for the first time after capturing the image
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
// operations
Param result = d.getData();
Parameters* param = new Parameters(result);
mDatabaseLeftCamera->addItem(param);
mModelLeftCamera->select();
ui->tableView->show();
}
// This is the doubleclick that re-opens the small dialog to change the name of the feature
void MainWindow::onTableClick(const QModelIndex &index)
{
int row = index.row();
Param currentData;
int ItemId = index.sibling(row, 0).data().toInt();
currentData.mName = index.sibling(row, 1).data().toString();
currentData.mSave = index.sibling(row, 2).data().toByteArray();
QPixmap iconPix;
if(!iconPix.loadFromData(index.sibling(row, 2).data().toByteArray())) {
}
clipSceneDialog d(this);
d.show();
d.setData(currentData);
d.setImage(iconPix.toImage());
if(d.exec() == QDialog::Rejected) {
return;
} else {
//
}
Param result = d.getData();
Parameters* param = new Parameters(result);
mDatabaseLeftCamera->updateItem(ItemId,param);
mModelLeftCamera->select();
ui->tableView->show();
}
For completeness see the error the compiler is giving if that helps:
I am sorry if this is trivial but I checked the updateItem(ItemId,param)
and thanks for shedding light on this.
Try and add some debug printing. Especially for the parameters that you add to the prepared statement. qry.addBindValue converts your value to a QVariant. Based on the documentation QVariants become NULL when they contain no data:
QVariant x(QString());
// x.isNull() == true
In case there is a problem retrieving your parameters, this could explain the violation of the NOT NULL constraints.

QObject::connect: signal not found in promoted widget with Lambda syntax

I have an overloaded QTreeWidget class, with my SIGNALS: I have promoted it in my UI and when I listen promoted QTreeWidget object with a lambda syntax I have an error.
QObject::connect: signal not found in CustomTreeWidget.
MY CustomTreeWidget looks like:
.h
class CustomTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
explicit CustomTreeWidget(QWidget *parent = 0);
~CustomTreeWidget() {
}
signals:
void currentNodeChanged(QSet<int> uids);
void deleteRequest(QVector<int> uids);
}
.cpp
CustomTreeWidget::CustomTreeWidget(QWidget *parent) : QTreeWidget(parent)
{
setAnimated(true);
connect(this, &CustomTreeWidget::customContextMenuRequested, this, [=](const QPoint &pos) {
this->m_bCustomMenuOpen = true;
const auto &&item = this->itemAt(pos);
QMenu myMenu;
bool ok = !(item) ? false : true;
if (ok) {
//თუ topLevelItem -ია მხოლოდ დამატების action -ი უნდა იყოს ჩართული.
if (item == this->topLevelItem(0) || item == this->topLevelItem(0)->child(0)) {
ok = false;
}
}
QAction *Removecnt = myMenu.addAction(tr("&წაშლა"), this, SLOT(DeleteNode()));
Removecnt->setIcon(QIcon(":/global_res/delete.png"));
Removecnt->setEnabled(ok);
myMenu.exec(this->mapToGlobal(pos));
});
}
void CustomTreeWidget::BFS(QTreeWidgetItem *item, QSet<int> &out)
{
std::queue<QTreeWidgetItem *> Q;
Q.push(item);
while (!Q.empty()) {
QTreeWidgetItem *now = Q.front(); Q.pop();
out.insert(this->m_mapUids[now]);
for (int i = 0; i < now->childCount(); i++) {
Q.push(now->child(i));
}
}
}
QSet<int> CustomTreeWidget::GetCurrentNodeUids()
{
QSet<int> uids;
if (!this->currentItem())
return uids;
this->BFS(this->currentItem(), uids);
return uids;
}
void CustomTreeWidget::DeleteNode()
{
QSet<int> nodes = this->GetCurrentNodeUids();
QVector<int> uids;
for (auto it : nodes) {
uids.push_back(it);
}
emit deleteRequest(uids);
}
My lambda looks like:
connect(ui->productTree, &CustomTreeWidget::deleteRequest, this, [=](QVector<int> uids) {
//logic
});
But this signal works with old syntax.
connect(ui->productTree, SIGNAL(deleteRequest(QVector<int>)), this, SLOT(checkSlot(QVector<int>)));
And this slot is.
void ProductForm::checkSlot(QVector<int> uids)
{
qDebug() << uids.size();
}
So what is problem lambda syntax?
This smells like the violation of the one definition rule (ODR) - perhaps due to a stale build folder. The problem is that the address of deleteRequest passed to the connect method is not the same as the address of the method visible from moc_CustomTreeWidget.cpp. Remove the build folder and try again. If it still doesn't work, start reducing your problem:
Create a minimization branch in the repository (if you're not using version control, you won't go anywhere with minimization).
Copy-paste the contents of the ui_CustomTreeWidget.h file into the CustomTreeWidget.cpp file, remove the #include line.
Inspect the pasted contents for instantiation of the productTree object with the correct type.
If that's correct, then remove everything else from the code, step-by-step, rebuilding and committing to the repository at each step that still reproduces. You should end up with a test case that is 20-30 lines long at most. And it'll be either obvious what's wrong, or you can modify the question with the test case.

How do you change a QGraphicsScene from another function?

My program has a QGraphicsView called SimulatorGV and it has a QGraphicsScene called Simulation. In the main function I have drawn a few rectangles and ellipses. I want to be able to draw on the same scene in another function too.
In essence, how do you add shapes to a scene from another function? (Which is called when a button on the user interface is pressed)
So far I've tried to pass the QGraphicsView to the other function? Below is the main ui function (irrelevant statements cut out):
{
ui->setupUi(this);
Simulation = new QGraphicsScene(this);
ui->SimulatorGV->setScene(Simulation);
Simulation->addRect(0,415,20,50,noPen,greyBrush);
Simulation->addRect(425,230,10,420,noPen,goldBrush);
Simulation->addEllipse(80,90,700,700,greyPen,noBrush);
Simulation->addRect(72,215,90,450,noPen,blackBrush);
}
In the header file I declared this function in the private slots:
void DrawingSimulation(QGraphicsView *SimulationGV);
Should it be like this instead?
void DrawingSimulation(QGraphicsScene *Simulation);
I called the function in another function like this:
DrawingSimulation(ui->SimulatorGV);
Should it be like this instead?
DrawingSimulation(ui->SimulatorGV->Simulation);
or?
DrawingSimulation(ui->Simulation);
This is the function I want to be able to draw on the scene from:
void RASP::DrawingSimulation(QGraphicsView *SimulationGV)
{
for (int i = 0; i < DisplayAlphaParticleNumber; i++)
{
if (ParticleLocation[i*6+3] != 0 || ParticleLocation[i*6+6] != 0)
{
ui->SimulatorGV->setScene(Simulation);
Simulation->addEllipse(ParticleLocation[i*6+3],ParticleLocation[i*6+4],10,10);
}
}
}
SimulatorGV is the name of the QGraphicsView in my ui form. RASP is the name of the project. ParticleLocation[i*6+3] is the x coordinate and [i*6+4] is the y coordinate.
Was I right to pass the QGraphicsView onto the varibale instead of the QGraphicsScene Simulation?
Did I pass it correctly?
In the DrawingSimulation function did I add the ellipse correctly?
Edit:
In essence, how do you add shapes to a scene from another function? (Which is called when a button on the user interface is pressed)
When a button is pressed this function is called:
void RASP::on_Button1_clicked()
{
//some values set
//some other functions called then the main one that leads to the drawingsimulation
mainfunction();
}
Then inside the mainfunction():
void RASP::mainfunction()
{
DrawingSimulation(); //is called
}
Now the function DrawingSimulation() which I would like to draw on the original scene in the RASP::RASP() (MyClass::MyClass) is called.
My previous attempt was to have a boolean function that is set true by the button then the addEllipse:
MyClass::MyClass()
{
ui->setupUi(this);
Simulation = new QGraphicsScene(this);
ui->SimulatorGV->setScene(Simulation);
Simulation->addRect(0,415,20,50,noPen,greyBrush);
Simulation->addRect(425,230,10,420,noPen,goldBrush);
Simulation->addEllipse(80,90,700,700,greyPen,noBrush);
Simulation->addRect(72,215,90,450,noPen,blackBrush);
if (SimulationRun == true)
{
for (int i = 0; i < DisplayAlphaParticleNumber; i++)
{
if (ParticleLocation[i*6+3] != 0 || ParticleLocation[i*6+6] != 0)
{
ui->SimulatorGV->setScene(Simulation);
Simulation->addEllipse(ParticleLocation[i*6+3],ParticleLocation[i*6+4],10,10);
}
}
}
}
and then in the button clicked function setting SimulationRun = to true.
Let's keep it simple.
If you have:
MyClass::MyClass() : ui(new Ui::MainWindow)
{
ui->setupUi(this);
Simulation = new QGraphicsScene(this);
ui->SimulatorGV->setScene(Simulation);
Simulation->addRect(0,415,20,50,noPen,greyBrush);
Simulation->addRect(425,230,10,420,noPen,goldBrush);
Simulation->addEllipse(80,90,700,700,greyPen,noBrush);
Simulation->addRect(72,215,90,450,noPen,blackBrush);
}
If this works, then, this will work too:
MyClass::MyClass() : ui(new Ui::MainWindow)
{
ui->setupUi(this);
Simulation = new QGraphicsScene(this); // supposing MyClass has a Simulation attribute of type QGraphicsScene
ui->SimulatorGV->setScene(Simulation);
addItems(); // calling function below
}
void MyClass::addItems()
{
// declared "void addItems();" in header file
addItems( Simulation ); // calling function below that could be static
}
void MyClass::addItems( QGraphicsScene* simu )
{
// declared "static void addItems(QGraphicsScene* simu);" in header file
simu->addRect(0,415,20,50,noPen,greyBrush);
simu->addRect(425,230,10,420,noPen,goldBrush);
simu->addEllipse(80,90,700,700,greyPen,noBrush);
simu->addRect(72,215,90,450,noPen,blackBrush);
}
Then, if this works, you now know how to modify the secene from "another function".
Finally, you should also have:
void MyClass::DrawingSimulation()
{
// declared "void DrawingSimulation();" in header file
DrawingSimulation( Simulation );
}
void MyClass::DrawingSimulation(QGraphicsScene *simu)
{
// declared "void DrawingSimulation(QGraphicsScene *simu);" in header file
for (int i = 0; i < DisplayAlphaParticleNumber; i++)
{
if (ParticleLocation[i*6+3] != 0 || ParticleLocation[i*6+6] != 0)
{
simu->addEllipse(ParticleLocation[i*6+3],ParticleLocation[i*6+4],10,10);
}
}
}
Note that DrawingSimulation() could also be a slot (declare it using public slots: in your header file. Then, if you connect it to the clicked() signal of a QPushButton of your GUI (for instance), it will be called when the button is clicked and ellipse will be added.
Like this:
MyClass::MyClass()
{
...
connect( ui->pushButton, SIGNAL(clicked()), this, SLOT(DrawingSimulation()) );
}

Undo stack remains empty in Qt

I am trying to undo/redo in multi document interface. I have different entities. Each entity has its own class. I have used UndoGroup but when I unable to push them to undoStack dont know whats's wrong there. Can anyone help me to solve the issue.
cadgraphicscene.cpp
CadGraphicsView::CadGraphicsView()
{
undoStack = new QUndoStack(this);
}
QUndoStack *CadGraphicsView::m_undoStack() const
{
return undoStack;
}
void CadGraphicsView::showUndoStack()
{
undoView = 0;
// shows the undoStack window
if (undoView == 0)
{
undoView = new QUndoView(undoStack);
undoView->setWindowTitle("Undo Stack");
}
undoView->show();
}
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
m_undoGroup = new QUndoGroup(this);
QAction *undoAction = m_undoGroup->createUndoAction(this);
undoAction->setShortcut(QKeySequence::Undo);
QAction *redoAction = m_undoGroup->createRedoAction(this);
redoAction->setShortcut(QKeySequence::Redo);
menuEdit->insertAction(menuEdit->actions().at(1), undoAction);
menuEdit->insertAction(undoAction, redoAction);
menuEdit->addAction(undoAction);
menuEdit->addAction(redoAction);
undoAction->setEnabled(true);
redoAction->setEnabled(true);
}
void MainWindow::updateActions()
{
CadGraphicsView *view = currentDocument();
m_undoGroup->setActiveStack(view == 0 ? 0 : view->m_undoStack());
}
void MainWindow::addDocument(CadGraphicsView *view)
{
m_undoGroup->addStack(view->m_undoStack());
connect(view->m_undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
connect(view->m_undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));
setCurrentDocument(view);
}
void MainWindow::setCurrentDocument(CadGraphicsView *view)
{
mdiArea->currentSubWindow();
}
CadGraphicsView *MainWindow::currentDocument() const
{
return qobject_cast<CadGraphicsView *>(mdiArea->parentWidget());
}
I am confused with why I am not able to push entities to undoStack. Please help me to solve this issue
I think the problem is in these two functions (see the inline comments):
void MainWindow::setCurrentDocument(CadGraphicsView *view)
{
// The view argument is not used at all. You do not set anything here.
mdiArea->currentSubWindow();
}
CadGraphicsView *MainWindow::currentDocument() const
{
// mdiArea->parentWidget() returns the MainWindow, so this function
// always returns 0.
return qobject_cast<CadGraphicsView *>(mdiArea->parentWidget());
// You should write it as
// return qobject_cast<CadGraphicsView *>(mdiArea->activeSubWindow()->widget());
}