QFileDialog custom layout - c++

I'm developing a file dialog to import file in my application and I want to have an additional QComboBox with a list of formats between File names edit and File of types filter combo box, like this:
I've managed to add QComboBox under filters like this:
using this code:
QGridLayout * layout = qobject_cast <QGridLayout *>(dialog->layout());
QLabel * labelFormat = new QLabel(tr("Format"), dialog);
layout->addWidget(labelFormat, 4, 0);
QComboBox * comboBoxFormat = new QComboBox(dialog);
layout->addWidget(comboBoxFormat, 4, 1);
But I need to swap the last two rows of this grid layout. I've tried something like this to swap rows:
QWidget * w0 = layout->itemAtPosition(3, 0)->widget();
QWidget * w1 = layout->itemAtPosition(3, 1)->widget();
QWidget * w2 = layout->itemAtPosition(3, 2)->widget();
QLabel * labelFormat = new QLabel(tr("Format"), dialog);
layout->addWidget(labelFormat, 3, 0);
QComboBox * comboBoxFormat = new QComboBox(dialog);
layout->addWidget(comboBoxFormat, 3, 1);
layout->replaceWidget(w0, labelFormat);
layout->replaceWidget(w1, comboBoxFormat);
layout->addWidget(w0, 4, 0);
layout->addWidget(w1, 4, 1);
layout->addWidget(w2, 4, 2);
But I got the wrong widgets position:
How can I achieve the widget positioning from the first screenshot?

In your case the problem is caused by the fact that you are incorrectly locating QDialogButtonBox, this must be in position 3, 2 occupying 2 rows and 1 column:
QGridLayout *layout = qobject_cast<QGridLayout *>(dialog->layout());
QWidget * w0 = layout->itemAtPosition(3, 0)->widget();
QWidget * w1 = layout->itemAtPosition(3, 1)->widget();
QWidget * w2 = layout->itemAtPosition(3, 2)->widget();
QLabel * labelFormat = new QLabel("Format", dialog);
layout->addWidget(labelFormat, 3, 0);
QComboBox * comboBoxFormat = new QComboBox(dialog);
layout->addWidget(comboBoxFormat, 3, 1);
layout->replaceWidget(w0, labelFormat);
layout->replaceWidget(w1, comboBoxFormat);
layout->addWidget(w0, 4, 0);
layout->addWidget(w1, 4, 1);
layout->addWidget(w2, 3, 2, 2, 1);

Related

Why is my QGraphicsLine in the wrong place

I want to draw a line to connect two circles (QGraphicsEllipseItem), but I find that I don't get the desired result with this way of writing.
//they have been initialized to the correct place
QGraphicsEllipseItem* nodeu;
QGraphicsEllipseItem* nodev;
this->addLine(nodeu->x(), nodeu->y(), nodev->x(), nodev->y());
The result of executing these codes is that only two circles appear, but no lines appear.
like this
My rough inference is the problem of coordinate transformation, but I just can't solve it.
thank you!
you should first add one QGraphicsView in your UI or :
QGraphicsView *graphicsView;
QGridLayout *gridLayout;
gridLayout = new QGridLayout(centralwidget);
gridLayout->setSpacing(0);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
graphicsView = new QGraphicsView(centralwidget);
graphicsView->setObjectName(QString::fromUtf8("graphicsView"));
gridLayout->addWidget(graphicsView, 0, 0, 1, 1);
then :
QGraphicsScene *_scene = new QGraphicsScene(this);
ui->graphicsView->setScene(_scene);
ui->graphicsView->setRenderHints(QPainter::Antialiasing);
QGraphicsEllipseItem *nodeu = new QGraphicsEllipseItem;
nodeu->setRect(20, 10, 20, 20);
_scene->addItem(nodeu);
QGraphicsEllipseItem *nodev = new QGraphicsEllipseItem;
nodev->setRect(80, 60, 20, 20);
_scene->addItem(nodev);
QGraphicsLineItem *_lineItem = new QGraphicsLineItem;
_lineItem->setLine(nodeu->rect().x() + nodeu->rect().width() / 2.0, nodeu->rect().y() + nodeu->rect().height() / 2.0,
nodev->rect().x() + nodev->rect().width() / 2.0, nodev->rect().y() + nodev->rect().height() / 2.0);
_scene->addItem(_lineItem);
this is the output:

Is it possible to add QTreeWidgetItem to QTableWidgetItem?

I have QTableWidget and I interested in how I can add QTreeWidget item into 3rd column in table? Is it possible?
I do it:
ui->tableWidget->insertRow(ui->tableWidget->rowCount());
ui->tableWidget->setCellWidget(ui->tableWidget->rowCount() - 1, 3, new QTreeWidget());
auto widget = dynamic_cast<QTreeWidget*>(ui->tableWidget->cellWidget(ui->tableWidget->rowCount() - 1, 3));
widget->setHeaderHidden(true);
QTreeWidgetItem * topLevel = new QTreeWidgetItem();
topLevel->setText(0, "This is top level");
widget->addTopLevelItem(topLevel);

Rendering in Vertical Layout fails to occur

I am trying to create a timeline app for visualization of certain time-sensitive requirements information and have begun experimentation with Qt since I am new to it. The problem I am having is that the rendered object will show up if I render it just basically on the main background, but when I tried to add the TimeLine objects to the vertical layout I have on my UI they refuse to render.
Here is my main window code for creating the objects:
void MainWindow::drawTimelines()
{
for(int i=0; i <= 3; i++)
{
TimeLine *tl = new TimeLine(this, this);
// ui->verticalLayout->addWidget(tl, 0, Qt::AlignLeft);
tl->lower();
QPoint * dest = new QPoint(this->width() - (this->width() / 12), i * this->height() / 4 + this->height() / 4);
QPoint * src = new QPoint(this->width() / 12, i * this->height() / 4 + this->height() / 4);
// tl->setGeometry(0, 0, this->width(), 100);
tl->setGeometry(src->x(), src->y(), this->width(), 100);
tl->updateGeometry();
QPoint *startPt = new QPoint(src->x(), 50);
QPoint *endPt = new QPoint(dest->x(), 50);
// QPoint *src = new QPoint(this->width() /8, 50);
// QPoint *dest = new QPoint(this->width() - (this->width() / 8), 50);
tl->setSrcPt(startPt);
tl->setDestPt(endPt);
tl->setNumSegments(3);
timeLineList.push_back(tl);
timeLineList.at(i)->show();
}
update();
}
Here is the maint function present in the TimeLine object itself:
void TimeLine::paintEvent(QPaintEvent * event)
{
QRectF frame(QPointF(sourcePoint->x(), sourcePoint->y()), geometry().size());
QPainter painter(this);
painter.setPen(QPen(Qt::FlatCap));
painter.drawRoundedRect(frame, 10.0, 10.0);
int translateAmount = sourcePoint->y() - window->getPainterY();
painter.translate(0, translateAmount);
// window->setPainterY(translateAmount);
painter.drawLine(sourcePoint->x(), 25, destPoint->x(), 25);
for(int i = 0; i <= numSegments; i++){
int xPoint = ((destPoint->x() - sourcePoint->x()) * i / numSegments) + sourcePoint->x();
int yPoint = 25;
painter.drawLine(xPoint, yPoint + 20, xPoint, yPoint - 20);
}
QWidget::paintEvent(event);
}
For reference, the verticalLayout is meant to have one
The TimeLines (and bounded rect boxes) do not render when I have the
// ui->verticalLayout->addWidget(tl, 0, Qt::AlignLeft);
uncommented. As you can see from a bunch of the other commented lines, I have tried numerous other things to try and render these TimeLines. I have tried:
changing reference points of the geometry to be (0,0) for the new segment of the vertical layout
changing the size of the geometry
both translating and not translating the painter
changing line thickness, type of line, etc.
even tried rendering something else simple in the vertical layout
The part that confuses me is that even the bounded rect made based on the geometry of the TimeLine frame gets cut off on the side and top of the timeline (it only shows top left corner and the top and left side-lines) even when rendered on the normal screen.

How do I align a widget?

I cannot move the widget into the layout (QGridLayout). You need to move the "label shift" to the other widgets. That they were close. How can I do that?
QLabel * label_answer = new QLabel(this);
label_answer->setText("label_shift");
label_answer->setFont(params_font);
label_answer->setObjectName(QStringLiteral("label_answer_%1").arg(count-1));
lay->addWidget(main_label, i,0, Qt::AlignLeft);
lay->addWidget(box_input_value, i, 1, Qt::AlignLeft);
lay->addWidget(label_answer, i, 2, Qt::AlignLeft); // label_shift
You could add a extra column to the gridlayout, have the spinbox span 2 columns, which would mean the space needed in the label row is after the label, instead of before it

QGridLayout issue with inserting widgets

(Using Qt 4.6.3, x64, linux)
I'm testing how to properly insert widgets into a existing a QGridLayout filled with various widgets. A broken down contrived case is the following:
QApplication app(argc,argv);
QWidget w;
QGridLayout* gl = new QGridLayout(&w);
QLabel* label = new QLabel("Image Size:");
QLineEdit* wedit = new QLineEdit("100");
QLabel* xlabel = new QLabel("x");
wedit->setAlignment(Qt::AlignRight);
gl->addWidget(label);
gl->addWidget(xlabel, 0, 1, 1, 1);
gl->addWidget(wedit, 0, gl->columnCount());
Which creates the following widget:
.
Assuming that have an existing QGridLayout as above, but without the "x" label, and I wished to insert this into the layout, switching the latter two addWidget lines might seem valid, i.e.:
\\ same as above
gl->addWidget(label);
gl->addWidget(wedit, 0, gl->columnCount());
gl->addWidget(xlabel, 0, 1, 1, 1);
This however, creates the following:
The gl->columnCount() after this is still 2, as both the x-label and the QLineEdit are filling the same cell. Based on this knowledge, the following code produces the initial desired result:
gl->addWidget(label);
gl->addWidget(wedit, 0, 2); // note: specified column 2, columnCount() is now 3
gl->addWidget(xlabel, 0, 1, 1, 1);
Though this is not particularly useful, as the original layout in question isn't built with later layouts in mind.
Since addWidget allows for specifying cell position, as well as row/column span, it seems odd that Qt wouldn't automatically replace the existing widgets in the layout. Does anyone have a suggestion as to how I might overcome this? I assume it would be possible to recreate a QGridLayout and copy into it the children of the original, taking care to insert the additional widget in the right location. This however is ugly, and susceptible to Qt version issues (as I want to modify a built in widget).
Edit:
I realize that I'm making the assumption of thinking in a QHBoxLayout way, where inserting a widget is uniquely understood, whereas in a QGridLayout this isn't the case (?).
I can clarify that I ultimately would like to modify QFileDialog::getSaveFileName, by inserting a widget (similar to the widget shown above) right above the two lower rows (i.e. above "File &Name:").
Thanks
Switching the latter two addWidget lines is not valid. For the following code:
gl->addWidget(label);
gl->addWidget(wedit, 0, gl->columnCount());
gl->addWidget(xlabel, 0, 1, 1, 1);
The arguments for the addWidget() calls are evaluated prior to adding the widget. Therefore, gl->columnCount() evaluates to one instead of two for the second call, since the column still has to be created. You are effectively adding two widgets to column one.
A possible solution is to re-add the widgets that should be relocated. I.e.
QLayoutItem* x01 = gl->itemAtPosition(0,1);
gl->addWidget(x01->widget(), 0, 2);
gl->addWidget(xlabel, 0, 1, 1, 1);
Now, this isn't particularly pretty, or easy to maintain, as a new version of Qt might change the original widget, and blindly handpicking and relocating children isn't that clever. The following real example (the one I actually wanted to solve) was to alter the Qt's "Save As" dialog window, that shows up using QFileDialog::getSaveFileName.
class ImageFileDialog : public QFileDialog {
public:
ImageFileDialog(QWidget* parent);
~ImageFileDialog();
QString getFileName() const;
QSize getImageSize() const;
QDialog::DialogCode exec(); // Overriden
protected:
void showEvent(QShowEvent* event); // Overriden
private:
QString fileName_;
QSize imageSize_;
QLineEdit* widthLineEdit_;
QLineEdit* heightLineEdit_;
};
And in the source (showing just constructor, focus handling and exec):
ImageFileDialog::ImageFileDialog(QWidget* parent)
: fileName_(""),
imageSize_(0,0),
widthLineEdit_(0),
heightLineEdit_(0)
{
setAcceptMode(QFileDialog::AcceptSave);
setFileMode(QFileDialog::AnyFile);
setConfirmOverwrite(true);
QGridLayout* mainLayout = dynamic_cast<QGridLayout*>(layout());
assert(mainLayout->columnCount() == 3);
assert(mainLayout->rowCount() == 4);
QWidget* container = new QWidget();
QGridLayout* glayout = new QGridLayout();
QLabel* imageSizeLabel = new QLabel("Image Size:");
widthLineEdit_ = new QLineEdit("400");
heightLineEdit_ = new QLineEdit("300");
widthLineEdit_->setAlignment(Qt::AlignRight);
heightLineEdit_->setAlignment(Qt::AlignRight);
container->setLayout(glayout);
glayout->setAlignment(Qt::AlignLeft);
glayout->addWidget(widthLineEdit_);
glayout->addWidget(new QLabel("x"), 0, 1);
glayout->addWidget(heightLineEdit_, 0, 2);
glayout->addWidget(new QLabel("[pixels]"), 0, 3);
glayout->addItem(new QSpacerItem(250, 0), 0, 4);
glayout->setContentsMargins(0,0,0,0); // Removes unwanted spacing
// Shifting relevant child widgets one row down.
int rowCount = mainLayout->rowCount();
QLayoutItem* x00 = mainLayout->itemAtPosition(mainLayout->rowCount()-2,0);
QLayoutItem* x10 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,0);
QLayoutItem* x01 = mainLayout->itemAtPosition(mainLayout->rowCount()-2,1);
QLayoutItem* x11 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,1);
QLayoutItem* x02 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,2);
assert(x00); assert(x01); assert(x10); assert(x11); assert(x02);
mainLayout->addWidget(x00->widget(), rowCount-1, 0, 1, 1);
mainLayout->addWidget(x10->widget(), rowCount, 0, 1, 1);
mainLayout->addWidget(x01->widget(), rowCount-1, 1, 1, 1);
mainLayout->addWidget(x11->widget(), rowCount, 1, 1, 1);
mainLayout->addWidget(x02->widget(), rowCount-1, 2, 2, 1);
// Adding the widgets in the now empty row.
rowCount = mainLayout->rowCount();
mainLayout->addWidget(imageSizeLabel, rowCount-3, 0, 1, 1 );
mainLayout->addWidget(container, rowCount-3, 1, 1, 1);
// Setting the proper tab-order
QLayoutItem* tmp = mainLayout->itemAtPosition(mainLayout->rowCount()-2,1);
QLayoutItem* tmp2 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,1);
assert(tmp); assert(tmp2);
QWidget::setTabOrder(heightLineEdit_ , tmp->widget());
QWidget::setTabOrder(tmp->widget(), tmp2->widget());
}
// Makes sure the right widget is in focus
void ImageFileDialog::showEvent(QShowEvent* event)
{
widthLineEdit_->setFocus(Qt::OtherFocusReason);
}
// Called to create the widget
QDialog::DialogCode ImageFileDialog::exec()
{
if (QFileDialog::exec() == QDialog::Rejected)
return QDialog::Rejected;
// The code that processes the widget form and stores results for later calls to
// getImageSize()
return QDialog:Accepted;
}
Which, using for instance
ImageFileDialog* dialog = new ImageFileDialog(&w);
dialog->exec();
Creates the following widget:
Comments and ways to do this better, or why this is just plain wrong are most welcome :)