I have a QVector of QObjects QVector<QWidget*> question_vector;. These widgets are questions. (My application is like a questionnaire thing).
When creating a questionnaire, question types are chosen from the selection on a comboBox, and within Questions class, the question is created, and stored in the QVector.
void CreateSurvey::comboBox_selection(const QString &arg1)
{
if(arg1 == "Single Line Text")
{
Question *singleLineText = new Question("Single Line Text");
surveyLayout->addWidget(singleLineText);
question_vector.append(singleLineText);
qDebug() << "Number of items: "<< question_vector.size();
} ...
}
void Question::create_singleLineEdit()
{
QVBoxLayout *vLayout = new QVBoxLayout;
QLabel *titleLabel = new QLabel("Title");
vLayout->addWidget(titleLabel);
QLineEdit *inputText = new QLineEdit;
vLayout->addWidget(inputText);
QLabel *commentsLabel = new QLabel("Comments");
vLayout->addWidget(commentsLabel);
QLineEdit *commentsText = new QLineEdit;
vLayout->addWidget(commentsText);
ui->frame->setLayout(vLayout);
}
This is what it looks like
The SingleLineEdit is the widget, the title, titleEdit, comments, commentsEdit.
How do I access, for example the text from an individual component of the widget, the commentsText QLineEdit?
Cast the element to the a QLineEdit:
QLineEdit *line_edit = dynamic_cast <QLineEdit *> (question_vector[3]);
if (line_edit)
{
QString text = line_edit->text();
}
This is a basic aspect of C++ programming; you probably should do some reading on C++ classes, how to derive them, how to use base class pointers and derived class pointers, and so on.
I think I've managed to solve what I was trying to do (at least partly)
So I had here
void Question::create_singleLineEdit()
{
QVBoxLayout *vLayout = new QVBoxLayout;
QLabel *titleLabel = new QLabel("Title");
vLayout->addWidget(titleLabel);
QLineEdit *inputText = new QLineEdit;
vLayout->addWidget(inputText);
QLabel *commentsLabel = new QLabel("Comments");
vLayout->addWidget(commentsLabel);
QLineEdit *commentsText = new QLineEdit;
vLayout->addWidget(commentsText);
ui->frame->setLayout(vLayout);
}
What I did was changed stuff like QLineEdit *commentsText = new QLineEdit; to
section_commentsText = newLineEdit; - Having QTextEdit *section_commentsText in my question.h.
I was then able to do
Question *object = question_vector[0];
QString text = object->section_commentsText->text();
qDebug() << text;
Related
I have a QTableView with my own implemented QAbstractItemModel, in which I can drag and drop multiple items inside. My problem is that when dragging the items and while trying to drop them in a destination cell, it is not so obvious for the user what the result is going to be. For example, I have the following,but I would prefer sth like the default widows displaying, which makes all 3 items like one item:
my QT Table
vs
windows dragging n dropping folders
After eyllanesc's suggestion for QPixmap, I found the correct solution to my problem, so that I can keep the mime data coming from my model. I have re-implemented startDrag(Qt::DropActions supportedActions) in my QTreeView class, so that when multiple objects are moved, one icon will be displayed along with the number of items moved. Now looks like this:
void MyTreeView::startDrag(Qt::DropActions supportedActions)
{
QModelIndexList indexes = selectedIndexes();
if (indexes.size() == 1)
return QAbstractItemView::startDrag(supportedActions);
if (indexes.count() > 0)
{
QMimeData *data = model()->mimeData(indexes);
if (!data)
return;
QRect rect;
rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
QDrag *drag = new QDrag(this);
ActionTreeItem* pItem = static_cast<ActionTreeItem*>(indexes[0].internalPointer());
if (pItem != NULL)
{
QPixmap pixmap = myIcon.pixmap(myIcon.actualSize(QSize(32, 32)));
QPainter *paint = new QPainter(&pixmap);
paint->setPen(Qt::black);
paint->setBrush(QBrush(Qt::white));
QRect numberRect(18, 18, 13, 13);
paint->drawRect(numberRect);
paint->drawText(numberRect, Qt::AlignHCenter | Qt::AlignVCenter, QString("%1").arg(indexes.count()));
drag->setPixmap(pixmap);
}
drag->setMimeData(data);
Qt::DropAction defaultDropAction = Qt::MoveAction;
drag->exec(supportedActions, defaultDropAction);
}
}
Taking this tutorial as a reference, the mousePressEvent method is overwritten, and a new QPixmap is placed in QDrag:
void mousePressEvent(QMouseEvent *event){
if (event->button() == Qt::LeftButton){
QDrag *drag = new QDrag(this);
drag->setMimeData(new QMimeData());
drag->setPixmap(QPixmap("image.png"));
drag->exec();
}
QTableView::mousePressEvent(event);
}
Output:
I'm storing QCheckBox in QTableWidget, in following way:
QCheckBox *checkBox = new QCheckBox();
QWidget *widget = new QWidget();
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->addWidget(checkBox);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0,0,0,0);
widget->setLayout(layout);
tableWidget->setCellWidget(row, 2, widget);
Then, I catch stateChanged() of the checkBox:
connect( checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxStateChanged(int)) );
void MainWindow::checkBoxStateChanged(int)
{
QCheckBox * box = qobject_cast< QCheckBox * >( sender() );
if( !box ) {
return;
}
}
Now, I can get to QTableWidget – it is box->parent()->parent()->parent(). Object before that, i.e. box->parent()->parent(), is qt_scrollarea_viewport (that's objectName()). I've searched children of the "viewport", and there's 16 QWidgets – the number of rows in my table. However, their children are only QHBoxLayout and QCheckBox. There apparently is no reference to QTableWidgetItem – it looks like if I were in some parallel object hierarchy, and QTableWidgetItem is in other hierarchy. Is that true? How to get the item?
See this question: How to work with signals from QTableWidget cell with cellWidget set
Adapted to you case:
void MainWindow::checkBoxStateChanged(int)
{
QCheckBox * box = qobject_cast< QCheckBox * >( sender() );
if (box)
{
int row = box->property("row").toInt();
int column = box->property("column").toInt();
QTableWidgetItem* item = tableWidget->item(row, column);
}
}
I have a QPushButton that will open new window on clicked.
void showNewWindow()
{
PopupWindow *popup = new PopupWindow();
popup->show();
}
And PopupWindow is declared as following:
class PopupWindow : public QWidget {
Q_OBJECT
public:
PopupWindow(QWidget* parent);
void setContent(QString content) { this->content = content; }
QString getContent() { return content; }
private:
QString content;
private slots:
void handleContinue();
void handleRunToEnd();
};
Then I implement a its constructor:
PopupWindow::PopupWindow(QWidget *parent):QWidget(parent)
{
QHBoxLayout *hlayout = new QHBoxLayout();
QWidget *buttonWidget = new QWidget();
QPushButton *btnContinue = new QPushButton();
btnContinue->setText("Continue");
QPushButton *btnRunEnd = new QPushButton();
btnRunEnd->setText("Run till completion");
buttonWidget->setLayout(hlayout);
hlayout->addWidget(btnContinue);
hlayout->addWidget(btnRunEnd);
connect(btnContinue,SIGNAL(clicked()), this, SLOT(handleContinue()));
connect(btnRunEnd,SIGNAL(clicked()), this, SLOT(handleRunToEnd()));
QTextEdit *html = new QTextEdit();
html->setReadOnly(true);
html->setText("AAAA");
QVBoxLayout *layout = new QVBoxLayout();
this->setLayout(layout);
layout->addWidget(html);
layout->addWidget(buttonWidget);
}
My problem: whenever I click on the "Continue" or "Run till completion" buttons on Popup Window. The app crashed. I could see the error as following:
QApplication: Object event filter cannot be in a different thread.
QApplication: Object event filter cannot be in a different thread.
QApplication: Object event filter cannot be in a different thread.
QWidget::repaint: Recursive repaint detected
Please, help me to resolve this.
I am trying to get the list of widgets from a .ui files.
So here is a bit of code:
QUiLoader loader;
QFile file(fname);
file.open(QFile::ReadOnly);
QWidget *myWidget = loader.load(&file, this);
file.close();
QStringList avlb_wd = loader.availableWidgets();
QMessageBox msg;
foreach (const QString &str, avlb_wd)
{
msg.setText(str);
msg.exec();
}
But as I can see, availableWidgets() gives me all the widgets, not the ones that are in .ui file.
How can I achieve it?
Thanks forward.
Make a subclass of QUiLoader, and reimplement createWidget, createLayout and createAction (there's also createActionGroup, but it's not really supported any more, unless you manually edit the ui file).
These functions are called every time a new widget, layout or action is created by the ui loader. So just call the base-class implementation to get the created object, and then you can gather whatever information you like, before returning it.
UPDATE:
So the basic QUiLoader subclass would look like this (add other overloads as required):
class UiLoader : public QUiLoader
{
Q_OBJECT
public:
UiLoader(QObject *parent = 0) : QUiLoader(parent) { }
virtual QWidget* createWidget(const QString &className,
QWidget *parent = 0, const QString &name = QString())
{
QWidget* widget = QUiLoader::createWidget(className, parent, name);
// do stuff with className, name, widget, etc
return widget;
}
};
I'm running a test to understand parent/child relationships in Qt and I have a question about how I can view these relationships in the Qt Creator Debugger.
When I start my demo application, here is what the debugger shows:
Because I call Qt's dumpObjectTree() before I add any widgets, the tree is empty, except for the MainWindow's layout. That's what I expected.
When I close the application, and the ~MainWindow destructor is called, I call dumpObjectTree() again, but this time, all of the widgets that I created show in the tree. If I called dumpObjectTree() after the window was destroyed, shouldn't the tree be empty again?
Am I not destroying the child widgets correctly, or do I misunderstand the information displayed by the dumpObjecTree() function?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
qDebug() << "WINDOW INITIALIZED-------------";
dumpObjectTree();
this->buildLayout();
}
void MainWindow::buildLayout() {
QWidget *window = new QWidget(this);
this->setObjectName("Main Window");
layout = new QVBoxLayout();
QSplitter *split = new QSplitter();
split->setObjectName("Horizontal Split");
split->setOrientation(Qt::Horizontal);
QTextEdit *editor1 = new QTextEdit();
editor1->setObjectName("Editor 1");
QTextEdit *editor2 = new QTextEdit();
editor2->setObjectName("Editor 2");
split->addWidget(editor1);
split->addWidget(editor2);
QSplitter *split2 = new QSplitter();
split2->setObjectName("Vertical Split");
split2->setOrientation(Qt::Vertical);
QTextEdit *editor3 = new QTextEdit();
editor3->setObjectName("Editor 3");
split2->addWidget(split);
split2->addWidget(editor3);
QToolBar *mainToolbar = new QToolBar();
mainToolbar->setObjectName("Main Toolbar");
mainToolbar->addAction("Main Button 1");
mainToolbar->addSeparator();
mainToolbar->addAction("Main Button 2");
mainToolbar->setMovable(true);
layout->addWidget(mainToolbar);
layout->addWidget(split2);
QToolBar *toolbar = new QToolBar(this);
toolbar->setObjectName("Mini Toolbar");
toolbar->addAction("Button 1");
toolbar->addSeparator();
toolbar->addAction("Button 2");
toolbar->setMovable(true);
QMenuBar *menu = new QMenuBar(this);
menu->setObjectName("Menu Bar");
menu->addAction("Menu 1");
menu->addAction("Menu 2");
menu->addAction("Menu 3");
window->setLayout(layout);
MainWindow::addToolBar(toolbar);
MainWindow::setMenuBar(menu);
MainWindow::setCentralWidget(window);
}
MainWindow::~MainWindow()
{
delete layout;
qDebug() << "DESTROYED " << this->metaObject()->className();
qDebug() << "OBJECT TREE-------------";
dumpObjectTree();
qDebug() << "OBJECT INFO-------------";
dumpObjectInfo();
}
Thanks
Your confusion is that when your MainWindow destructor is called, the window is only part of the way through being destroyed.
In particular, the child widgets do not get deleted through the parent-child mechanism until the QObject destructor is called, which occurs after that, so at the point you call dumpObjectTree() all the children still exist.