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

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");
}

Related

Close button only on active tab of QTabWidget

To save space in a QTabWidget, I would like to show the close icon only for the current tab, like e.g. Firefox is doing:
Is there a simple way using a style sheet, some thing like (not working like this)
QTabBar::tab::!selected::close-button {visible: false;}
or do I have to subclass QTabWidget to get the desired behavior?
You won't need to subclass anything, you can use QTabWidget::tabBar() method to obtain a reference (i.e. QTabBar *) to the tab bar associated with your QTabWidget. (Note that this method is no longer protected, so it can be accessed without subclassing the class)
QTabBar *tabBar = tabWidget->tabBar();
You can now use tabBar reference to hide close buttons on non-current tabs. For example to hide ith button, you can do:
tabBar->tabButton(i, QTabBar::RightSide)->hide();
So a simple workflow could be as follows:
Connect QTabWidget::currentChanged(int index) signal to a slot.
In that slot hide all close buttons other than the button at index.
You can subclass QTabWidget to get access to the QTabBar widget using protected method QTabWidget::tabBar. Then you can connect to the QTabBar::currentChanged signal and hide close button for not selected tabs manually:
QTabBar::ButtonPosition closeSide =
(QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
for (int i = 0; i < toolbar->count(); ++i)
{
if (i != toolbar->currentIndex())
{
QWidget *w = toolbar->tabButton(i, closeSide);
w->hide();
}
}
hide() leaves empty space for the invisible close button. This looks funny.
Set the width to 0 instead.

How to reset QLineEdit text by pressing Escape key?

I'm working on a Qt4 project. I have a QLineEdit and I want to re-use behavior that I see when I click the Escape key inside the QLineEdit, but I'm not sure how.
When I press the escape key, I get the field to reset to the value that it was before I started editing. This is useful to me and I want this behavior on-hand.
Ideally, I would like a signal I can fire off that triggers the QLineEdit to reset to the value it was before. I would prefer not to try and fake an escape key event. I can cache the old value of the line edit, but this seems more work if the behavior already exists when I click escape. Thanks.
How can I make QLineEdit widget to respond on Escape key by setting
the text programmatically?
Either by overriding QWidget::event virtual function with the child of QLineEdit or a bit more "local", like installing the event filter:
class MyLineEditEventFilter : public QObject
{
public:
explicit MyLineEditEventFilter(QLineEdit *parent) : QObject(parent)
{}
bool eventFilter(QObject *obj, QEvent *e)
{
switch (e->type())
{
case QEvent::KeyPress:
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
if (keyEvent->key() == Qt::Key_Escape)
{
// or set the other text from the variable
reinterpret_cast<QLineEdit *>(parent())->setText("Escape!");
}
break;
}
}
// standard event processing
return QObject::eventFilter(obj, e);
}
};
And the caller is like that:
m_pLineEditSearch = new QLineEdit;
auto* pLineEditEvtFilter = new MyLineEditEventFilter(m_pLineEditSearch);
m_pLineEditSearch->installEventFilter(pLineEditEvtFilter);
For getting the previous text to reset with Escape pressed you may use different methods but you need to obtain the pointer to the object holding the string somehow. That is hard to answer without seeing your code.
You can also use QDataWidgetMapper and map your QLineEdit to its model. The Esc key behavior you're mentioning is already built-in there. You can also take advantage of the other functionalities that QDataWidgetMapper provides.
Here's how you would use it:
//Your model can have multiple rows and columns, let's assume it's just one
//QLineEdit, that will mean one row and one column
QStandardItemModel *model = new QStandardItemModel(1,1,this);
QStandardItem* item = new QStandardItem("QLineEdit initial value");
QLineEdit* myLineEdit = new QLineEdit(this);
QDataWidgetMapper* dataWidgetMapper = new QDataWidgetMapper(this);
dataWidgetMapper->setModel(model);
dataWidgetMapper->addMapping(myLineEdit, 0);
dataWidgetMapper->toFirst();
Hope this helps.
UPDATE:
There have been some valid concerns raised in the comments under my section about some of the pitfalls of QDataWidgetMapper, namely the fact that it not only responds to Escape key but also other keys like Enter/Return. So what happens is that after calling QDataWidgetMapper::addMapping(QWidget*, int) an event filter will be installed on your widget, which will consume Escape and Enter/Return keys. If you are still interested in finding out whether Enter or Escape have been pressed, you can add one more event filter right after that where you can check for other keys pressed. I have tried it and it works.

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

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));
}
}

QTreeWidget editItem fails with "edit: editing failed"

I have a QTreeWidgetItem added to a QTreeWidget:
QTreeWidgetItem* item = new QTreeWidgetItem(ui->trwPairs);
item->setFlags(item->flags() | Qt::ItemIsEditable);
If the item is edited, I want to do a few checks on the new value:
Pairs::Pairs(QWidget *parent) :
QWidget(parent),
ui(new Ui::Pairs)
{
ui->setupUi(this);
connect(this->ui->trwPairs, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(Validate(QTreeWidgetItem*,int)));
}
void Pairs::Validate(QTreeWidgetItem* item, int column)
{
if (item->text(column).toInt() < 1)
{
QMessageBox::critical(this, "Error", QString("Node ID ") + item->text(column) + " is invalid.");
ui->trwPairs->editItem(item, column);
}
}
Naturally, if it's less than 1, it catches it, and gives me the message box. However, printed to cerr is edit: editing failed and the item is not in edit mode. What am I missing?
Stepping through it in the debugger reveals the following:
In quabstractitemview.cpp line false is returned on line 3953. Somehow it looks like your item is still in editing state and you are trying to edit it again or something.
bool QAbstractItemViewPrivate::shouldEdit(QAbstractItemView::EditTrigger trigger,
const QModelIndex &index) const
{
// ..
if (state == QAbstractItemView::EditingState)
return false;
}
IIRC I had a similar problem with tables with multiple lines per cell. Check out the classes QAbstractItemDelegate views have item delegates which allow you to control which editor is used and how it behaves. I believe by default the QLineEdit is used. Editors like QLineEdit can have validators which control how the data is validated, in your case reject it if the numerical value is < 0. But I think you have to use the model / view classes and implement your own model for that. The Qt documentation for QTreeWidget::setItemWidget(..) says:
This function should only be used to display static content in the place of a tree widget item. If you want to display custom dynamic content or implement a custom editor widget, use QTreeView and subclass QItemDelegate instead.
I am not sure however if there is a simpler way to do this using the widget classes.
The problem could be, that you are setting the flags for your items in a very strange way.
Simply enable both item-selection, and edit:
item->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
I had a similar issue where I was attempting to edit the subsequent column upon receiving the itemChanged signal. Based on Nils' analysis that the item was still in the edit state, I changed the signal connection type to QueuedConnection, which allowed the item to leave the state before re-entering it.
I had a similar problem where I'd get the 'edit: editing failed' error when invoking edit() via a shortcut key. I was passing currentIndex() to edit(), but I wasn't checking that the correct column of the selected row was current. I only had the first column editable, so if I had clicked the row (but in any other column) and then invoked my edit key I'd get the error.
I was able to solve my problem by passing the result of sibling(currentIndex().row(), 0) to edit() instead.

Fail to clear QLineEdit after selecting item from QCompleter

using PopupCompletion mode when you select an item (using arrow keys) and press return - lineEdit should become empty (i clear lineEdit when return is pressed), but lineEdit does not become empty. (If you press 'Enter' again it will empty the lineEdit). So i think pressing return does clear lineEdit, but pressing return also tells QCompleter to insert selected item into lineEdit, so it seems like nothing happens.
But, if you click the item insted of selecting it with arrows - everything works fine.
I tried to find the solution on the internet, but i found only one person that had the same problem: http://lists.trolltech.com/qt-interest/2006-10/thread00985-0.html . Sadly there are no answers. Please read his question because it will help understand my problem.
How can I clean LineEdit after QCompleter inserted selected item? (catching activated signal does not help)
The issue here is that the completer actually contains a pop-up, which is actually a separate QAbstractItemView widget (refer to the QCompleter::popup() documentation). As such, when you press 'Enter' on the QCompleter, the key event actually goes to the pop-up and not the line edit.
There are two different ways to resolve your issue:
Option 1
Connect the completer's activated signal to the line edit's clear slot, but do it as a QueuedConnection:
QObject::connect(completer, SIGNAL(activated(const QString&)),
lineEdit, SLOT(clear()),
Qt::QueuedConnection);
The reason why using a direct connection doesn't work is because your are essentially dependent on the order in which slots get called from a signal. Using a QueuedConnection gets around this. From a code maintenance standpoint, I don't really prefer this solution because it isn't clear what your intention is just by looking at the code.
Option 2
Write an event filter around the pop-up to filter out the 'Enter' key to clear the line edit explicitly. Your event filter would end up looking something like this:
class EventFilter : public QObject
{
Q_OBJECT
public:
EventFilter(QLineEdit* lineEdit, QObject* parent = NULL)
:QObject(parent)
,mLineEdit(lineEdit)
{ }
virtual ~EventFilter()
{ }
bool eventFilter(QObject* watched, QEvent* event)
{
QAbstractItemView* view = qobject_cast<QAbstractItemView*>(watched);
if (event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return ||
keyEvent->key() == Qt::Key_Enter)
{
mLineEdit->clear();
view->hide();
return true;
}
}
return false;
}
private:
QLineEdit* mLineEdit;
};
You would then install the event filter on the completer's pop-up:
EventFilter* filter = new EventFilter(lineEdit);
completer->popup()->installEventFilter(filter);
This option is more work, but it's clearer as to what you are doing. Moreover, you can perform additional customization this way, if you prefer.