Qt: add a file selection field on the form (QLineEdit and "browse" button) - c++

I need to display QLineEdit with "Browse" button at my form. When user clicks button, QFileDialog should be opened, and so on.
This is pretty common thing, but I can't find ready-made solution for that. I expected in Qt Designer some widget like QFileSelect, or something like that, but found nothing similar.
Should I implement it by hand? Or, what is the correct way to do this?

Should I implement it by hand? Or, what is the correct way to do this?
Yes, I agree with you that it is a common thing, but unfortunately you will need to implement this yourself. The good news is that you can do this easily by something like this:
MyMainWindow::createUI()
{
label = new QLabel("foo");
button = new QPushButton("Browse");
connect(button, SIGNAL(clicked()), SLOT(browse()));
layout = new QHorizontalLayout();
layout->addWidget(label);
layout->addWidget(button);
setLayout(layout);
}
void MyMainWindow::browse()
{
QString directory = QFileDialog::getExistingDirectory(this,
tr("Find Files"), QDir::currentPath());
if (!directory.isEmpty()) {
if (directoryComboBox->findText(directory) == -1)
directoryComboBox->addItem(directory);
directoryComboBox->setCurrentIndex(directoryComboBox->findText(directory));
}
}

Related

QAbstractItemView Tab Focus While Editing Item

I have a QTreeView populated with items from a model. When a call to edit() is made on an index, a custom editor displays. The editor consists of two QLineEdit widgets.
I want the focus to switch between the two QLineEdit widgets when Tab is pressed. However, pressing Tab cycles through everything else on my program. All my QPushButton and QTabWidget objects are included in the Tab order even though they are completely different widgets than my editor.
I've tried setting the tab order using setTabOrder() to loop it between the two QLineEdit widgets, however this still doesn't isolate the editor widget from the surrounding widgets. Why is this happening?
NOTE: I'm not trying to disable tab ordering anywhere else, just isolate it to my editor for the time being.
Thanks for your time!
This can be easily implemented using QWidget::focusNextPrevChild as follows:
class EditWidget : public QWidget
{
public:
EditWidget(QWidget *pParent) : QWidget(pParent)
{
QHBoxLayout *pLayout = new QHBoxLayout(this);
setLayout(pLayout);
pLayout->addWidget(m_pEdit1 = new QLineEdit ());
pLayout->addWidget(m_pEdit2 = new QLineEdit ());
}
bool focusNextPrevChild(bool next)
{
if (m_pEdit2->hasFocus())
m_pEdit1->setFocus();
else
m_pEdit2->setFocus();
return true; // prevent further actions (i.e. consume the (tab) event)
}
protected:
QLineEdit *m_pEdit1;
QLineEdit *m_pEdit2;
};

How can I verify if the checkbox is checked or not in Qt?

The following code is supposed to set the text of nameLine form to this box is unchecked when the QCheckBox instance checkbox has state Unchecked.
Here is the my checkbox instance declaration:
QCheckBox *checkbox = new QCheckBox("paid with cash!", this);
checkbox->setCheckState(Qt::Unchecked);
and here is the logic so far:
if(checkbox->checkState(Qt::Unchecked))
{
nameLine->setText("the box is unchecked");
}
This code does not compile. The resulting error is the following:
C:\Qt\5.1.1\mingw48_32\examples\widgets\tutorials\addressbook\part1\voruskra.cpp:144: error: no matching function for call to 'QCheckBox::checkState(Qt::CheckState)'
if(checkbox->checkState(Qt::Unchecked))
^
Can you tell me what I am doing wrong?
Unless you are using a tristate checkbox, you can simply if (checkbox->isChecked())
This property is inherited way back in QAbstractButton. If it is a tristate checkbox, you will have to use checkState() as suggested in the other answer.
I think checkState doesn't take any argument. Try if(checkbox->checkState() == Qt::Unchecked)
maybe you can try like this?
QCheckBox *checkbox = new QCheckBox("paid with cash!", this);
checkbox->setChecked(false);
then for if command..
if(!checkbox->isChecked)
{
nameLine->setText("the box is unchecked");
}

Add widget with editable properties through code

I've created a custom widget plugin that is a container( it overloads the qframe). In this container i would like to add children through the code. I've succeeded in doing this. However the children aren't editable or clickable in the designer. I know for children to be editable through the designer, they should be added as code to the XML, but i don't know how to do this.
Would anybody know if it's at all possible to do this?
The code I have, with arrowedFrame as my custom widget plugin class:
arrowedFrame::arrowedFrame(QWidget *parent, Qt::WindowFlags f) : (parent, f)
{
QLabel* testLabel = new QLabel(this);
}
this adds a new Label, as member (sorry i can't yet post pictures, but imagine a box with a label in it). But as i said this label isn't at all editable through the designer.
The solution I found to this is by taking this guide. And adding some things in the initialize function:
void PlotContainerPlugin::initialize(QDesignerFormEditorInterface *formEditor)
{
if (initialized)
return;
QExtensionManager *manager = formEditor->extensionManager();
myFormEditor = formEditor;
Q_ASSERT(manager != 0);
manager->registerExtensions(factory, Q_TYPEID(QDesignerContainerExtension));
initialized = true;
}
The first part just gets a manager:
QExtensionManager *manager = formEditor->extensionManager();
And then we use this manager to,
manager->registerExtensions(factory, Q_TYPEID(QDesignerContainerExtension));
register the plugin(a plotter I my case) with the designer.
Hope this helps:)

How to change contents of QMainWindow dynamically

I have a QMainWindow that starts out with nothing but a menubar with a menu that has two options. When the first is clicked the window should be populated with QLabels and various input widgets to recieve data. When the second option is clicked the window should be populated with a QTextEdit(obviously removing whatever was on the window at the time)
The following is code I have tried :
void OrderWindow::displayAddOrder(){
QVBoxLayout* tlayout = new QVBoxLayout();
QHBoxLayout* row = new QHBoxLayout();
row->addWidget(nameLbl);
tlayout->addLayout(row);
qDeleteAll(children());
delete layout();
setLayout(tlayout);
}
It's a bit messy since I've been trying various things. When I click on a menu option with this code it simply says the application has stopped working.
Any help would be appreciated.
You have at least the following options:
Always show the actual widget, and hide the rest. This is simple in case of two widgets like in your example. You could use this technique with the observer design pattern for any number of widgets.
Use the QStackedWidget class which basically behaves the way as your custom observer pattern implementation would be, although you will need to use an extra class for this.
Therefore, I would suggest to write the following code:
orderwindow.h
...
class QStackedWidget;
class OrderWindow
{
...
public:
explicit OrderedWindow(QWidget *parent);
...
private:
QStackedWidget m_stackedWidget;
...
}
...
orderwindow.cpp
#include "orderwindow.h"
#include <QStackedWidget>
...
OrderWindow::OrderWindow(QWidget *parent)
: QWidget(parent)
, m_stackedWidget(new QStackedWidget(this))
{
QWidget *firstPageWidget = new QWidget;
QWidget *secondPageWidget = new QWidget;
m_stackedWidget->addWidget(firstPageWidget);
m_stackedWidget->addWidget(secondPageWidget);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(stackedWidget);
setLayout(layout);
}
...
void OrderWindow::displayAddOrder() {
m_stackedWidget->setCurrentWidget(nameLbl);
}
...
you can use a QStackedWidget
start with showing an empty page and then show the correct page as needed:
there is then no need to mess with adding or removing widgets
Yes, you can use a QStakedWidget if your input options are fixed. If it's not, I suggest you to use an abstract factory pattern to create the stacked widget content. This woluld make your code more readable.

QInputDialog with Multiline text

I need to create a text input dialog with multiple lines. Is there any way to do this using QInputDialog?
If not, is the simplest recommendation to subclass QPlainTextEdit?
QInputDialog and more precisely getText work only with a QLineEdit.
Just implement a small dialog sublass which contains a QPlainTextEdit. Shouldn't be too much work. Not as fast as QInputDialog, but not too much effort either.
Update: since version Qt 5.2, QInputDialog has getMultiLineText.
I was able to do that using QInputDialog and setting QInputDialog::UsePlainTextEditForTextInput.
However, one issue that I found was that QInputDialog was always selecting the text in the dialog (in exec()) and there is no flag to prevent that. The workaround was to connect the change in the selection to a lambda that deselects everything:
auto noteDialog = new QInputDialog(this);
noteDialog->setOptions(QInputDialog::UsePlainTextEditForTextInput);
noteDialog->setWindowTitle("Title");
noteDialog->setLabelText("Notes:");
noteDialog->setTextValue("text");
auto lineEdit = noteDialog->findChild<QPlainTextEdit*>();
connect(lineEdit, &QPlainTextEdit::selectionChanged, [lineEdit](){
if(lineEdit->textCursor().hasSelection())
{
QTextCursor cursor = lineEdit->textCursor();
cursor.clearSelection();
cursor.movePosition(QTextCursor::End);
lineEdit->setTextCursor(cursor);
}
});
bool ok = noteDialog->exec();
if (ok)
doSomething(noteDialog->textValue());
If you are fine with the selected text, QInputDialog::getMultiLineText alone should do the trick.
I needed this to work in Qt4 and this was one of the very few questions I found asking about it, none had any implementations as answers. I've just managed to replicate the functionality and look of Qt5 however, so even though it's in Python, I may as well post here as it could come in useful to others.
To get it working, it needed its own layout, and since QInputDialog builds the layout, QDialog had to be subclassed. I then added getMultiLineText to QInputDialog, which returns a reading from the QPlainTextEdit and the result of the new dialog.
class _QInputDialogMultiline(QDialog):
"""Build a replica interface of QInputDialog.getMultilineText."""
def __init__(self, parent, title, label, text='', **kwargs):
super(_QInputDialogMultiline, self).__init__(parent, **kwargs)
if title is not None:
self.setWindowTitle(title)
self.setLayout(QVBoxLayout())
self.layout().addWidget(QLabel(label))
self.textEdit = QPlainTextEdit()
self.layout().addWidget(self.textEdit)
buttonLayout = QHBoxLayout()
buttonLayout.addStretch()
okButton = QPushButton('OK')
buttonLayout.addWidget(okButton)
cancelButton = QPushButton('Cancel')
buttonLayout.addWidget(cancelButton)
self.layout().addLayout(buttonLayout)
self.textEdit.setPlainText(text)
self.textEdit.selectAll()
okButton.clicked.connect(self.accept)
cancelButton.clicked.connect(self.reject)
class QInputDialog(QInputDialog):
#classmethod
def getMultiLineText(cls, parent, title, label, text='', **kwargs):
dialog = _QInputDialogMultiline(parent, title, label, text, **kwargs)
result = dialog.exec_()
return (str(dialog.textEdit.toPlainText()), bool(result))
Example to show they look the same:
QInputDialog.getMultiLineText(None, 'Window Title', 'This is a label.', 'Initial text')
Qt4 (my code):
Qt5 (standard code):
To retrieve the user's input from QInputDialog::getText() into an expandable string:
bool ok;
std::string* comment = new std::string;
QString qComment = QInputDialog::getText(0,
"<title_of_input_dialog_displayed_at_top>",
"<label_of_input_field_displayed_at_left>",
QLineEdit::Normal, "<enter_this_or_that_here>", &ok);
if (ok && !qComment.isEmpty()) {
QByteArray qba = qComment.toLocal8Bit();
comment->assign(qba.data(), qba.size());
} else if (ok) { // user clicked Ok but did not enter text
comment->assign("<default_user_input>");
} else { // user clicked Cancel
...
}
delete comment;