I am trying to create a menu app (like windows search) with QCompleter.
I would like to show all items from completer when the QLineEdit is empty.
And it works first time, but when I start typing something into the lineEdit and I delete all characters from lineEdit, and then press Enter I see nothing. Where is my mistake?
My code is below.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
this->wordList << "alpha" << "omega" << "omicron" << "zeta" << "icon";
this->lineEdit = new QLineEdit(this);
completer = new QCompleter(wordList, this);
completer->setCaseSensitivity(Qt::CaseInsensitive);
lineEdit->setCompleter(completer);
completer->QCompleter::complete();
ui->setupUi(this);
}
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter))
{
if(lineEdit->text()=="")
{
completer->complete();
}
if(wordList.contains(lineEdit->text(),Qt::CaseInsensitive))
qDebug() <<"CATCH IT";
}
}
Could you please advise me?
You need to reset the completion prefix on the completer.
if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
{
if(lineEdit->text().isEmpty())
{
lineEdit->completer()->setCompletionPrefix("");
lineEdit->completer()->complete();
}
}
Also if the intent is to only have it populate when return is pressed in the line edit, you will want to create your own line edit to handle that versus using the main window.
Related
I have a dialog AlarmSetup derived from QDialog with following button arrangement:
// button box
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel |ButtonBox::Help, Qt::Horizontal, this);
buttonBox->button(QDialogButtonBox::Ok)->setText("übernehmen");
buttonBox->button(QDialogButtonBox::Cancel)->setText("abbrechen");
buttonBox->button(QDialogButtonBox::Help)->setText("Hilfe");
connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotOk()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(slotCancel()));
connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(slotHelp()));
From a second dialog AlarmWindow, I have a slot AlarmWindow::slotOpen() in which I am creating a new instance of AlarmSetup and evaluating the return code of AlarmSetup::exec():
void AlarmWindow::slotOpen() // we create a new instance of AlarmSetup
{
if ( DBG_ALARM ) qDebug() << "AlarmWindow::slotOpen() triggered";
int alarmId = mAlarm.getAlarmIdFromAlarmMap( objectName() );
AlarmData alarmData = mAlarm.mAlarmMap.value( alarmId );
//qDebug() << "alarmData:" << alarmData << "| alarmId:" << alarmId;
AlarmSetup* alarmSetup = new AlarmSetup( mAlarm, alarmData, alarmId );
int res = alarmSetup->exec();
qDebug() << "AlarmWindow -> AlarmSetup() returned:" << (res==QDialog::Accepted? "QDialog::Accepted":"QDialog::Rejected");
...
}
res is always QDialog::Rejected, independly which button I clicked in AlarmSetup!
The corresponding buttons are standard button QDialogButtonBox::Ok and QDialogButtonBox::Cancel respectively, the corresponding signals SIGNAL(accepted()) and SIGNAL(rejected()) respectively, so I do not understand why the return value is wrong!
Note that the dialog AlarmSetup is working as expected.
Any solution to get return value res working?
Thank you for your time.
here is the code of slotOK()
void AlarmSetup::slotOk()
{
if (DBG_ALARM) qDebug() << "AlarmSetup::slotOk() triggered";
QTime time = timeBox->time();
time.addSecs(60); // next full minute
time.setHMS( time.hour(), time.minute(), 0 );
AlarmData alarmData( alarmActiveBox->isChecked()
, QDateTime( calendar->selectedDate(), time )
, titleBox->text()
, textBox->document()->toPlainText()
, alarmSound->isChecked()
, alarmSoundBox->text()
, alarmRepeatActive->isChecked()
, numBox->text().toInt()
, unitBox->currentText()
, mFileName );
//qDebug() << "data from Setup:" << alarmData;
emit signalSetAlarm( alarmData, mAlarmId );
close();
}
Call accept(); or reject(); instead of close(). Rejected is just the default value (as by pressing ESC key).
Change your slots to return the desired value.
Update:
This works for me:
Mainwindow (removed irrelevant methods):
void MainWindow::openDialog()
{
Dialog* dialog = new Dialog();
dialog->setModal(true);
int result = dialog->exec();
qDebug()<<"Result:"<<result;
}
Dialog (removed irrelevant methods):
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
buttonBox->button(QDialogButtonBox::Ok)->setText("übernehmen");
buttonBox->button(QDialogButtonBox::Cancel)->setText("abbrechen");
connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotOk()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(slotCancel()));
}
void Dialog::slotOk()
{
accept();
//close();
}
void Dialog::slotCancel()
{
reject();
}
With close() instead of accept() I receive 0 for result too. This may be due to being in the button box and not gaining the correct role, not sure though.
Did you override QDialog::exec() or QDialog::accept()?
Sample:
Label::Label(QLabel *parent) :
QLabel(parent)
{
this->show();
this->resize(200, 200);
}
void Label::mousePressEvent(QMouseEvent *event)
{
this->resize(300, 300);
}
Expected result: when i press label by touching, the label will become bigger.
Actual result: when i release or move my finger, it become bigger.
Its looks like the mousePressEvent is not detected.
BTW QML also have same problem for MouseArea onPressed
Thanks for answering, i tried to add this:
bool Label::event(QEvent *e)
{
if(e->type() == QEvent::TouchBegin)
qDebug() << "TouchBegin";
if(e->type() == QEvent::TouchCancel)
qDebug() << "TouchCancel";
if(e->type() == QEvent::TouchEnd)
qDebug() << "TouchEnd";
if(e->type() == QEvent::TouchUpdate)
qDebug() << "TouchUpdate";
return e->isAccepted();
}
But the TouchBegin event still not be detected when i pressed.
I have a QTableWidget that is displayed in the user interface that I can add and remove rows and columns using buttons. The problem is, when I add a row or column, I can change the data in the actual cells, but I cannot name the row or column. The name is simply a static number.
Is there a way to allow the user of my program to perhaps double-click on a row/column header and edit the name in-line or something similar?
Thanks.
As far as I know there is no built-in way to do this. However this can be implemented manually. The main idea of the following code is to detect double clicks on header items, place QLineEdit over them and save edited text once it loses focus. The example is based on Qt generated Designer Form Class with a table named ui->tableWidget which can be either QTableWidget or QTableView.
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QLineEdit* header_editor;
int editor_index;
bool eventFilter(QObject*, QEvent*);
};
Source:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
header_editor = 0;
ui->setupUi(this);
ui->tableWidget->horizontalHeader()->viewport()->installEventFilter(this);
ui->tableWidget->verticalHeader()->viewport()->installEventFilter(this);
}
MainWindow::~MainWindow() {
delete ui;
}
bool MainWindow::eventFilter(QObject* object, QEvent* event) {
if ((object == ui->tableWidget->horizontalHeader()->viewport() ||
object == ui->tableWidget->verticalHeader()->viewport()) &&
event->type() == QEvent::MouseButtonDblClick) {
if (header_editor) { //delete previous editor just in case
header_editor->deleteLater();
header_editor = 0;
}
QMouseEvent* e = static_cast<QMouseEvent*>(event);
QHeaderView* header = static_cast<QHeaderView*>(object->parent());
int mouse_pos = header->orientation() == Qt::Horizontal ? e->x() : e->y();
int logical_index = header->logicalIndex(header->visualIndexAt(mouse_pos));
if (logical_index >= 0) { // if mouse is over an item
QRect rect; // line edit rect in header's viewport's coordinates
if (header->orientation() == Qt::Horizontal) {
rect.setLeft(header->sectionPosition(logical_index));
rect.setWidth(header->sectionSize(logical_index));
rect.setTop(0);
rect.setHeight(header->height());
} else {
rect.setTop(header->sectionPosition(logical_index));
rect.setHeight(header->sectionSize(logical_index));
rect.setLeft(0);
rect.setWidth(header->width());
}
rect.adjust(1, 1, -1, -1);
header_editor = new QLineEdit(header->viewport());
header_editor->move(rect.topLeft());
header_editor->resize(rect.size());
header_editor->setFrame(false);
//get current item text
QString text = header->model()->
headerData(logical_index, header->orientation()).toString();
header_editor->setText(text);
header_editor->setFocus();
editor_index = logical_index; //save for future use
header_editor->installEventFilter(this); //catch focus out event
//if user presses Enter it should close editor
connect(header_editor, SIGNAL(returnPressed()),
ui->tableWidget, SLOT(setFocus()));
header_editor->show();
}
return true; // filter out event
} else if (object == header_editor && event->type() == QEvent::FocusOut) {
QHeaderView* header = static_cast<QHeaderView*>(
header_editor->parentWidget()->parentWidget());
//save item text
header->model()->setHeaderData(editor_index, header->orientation(),
header_editor->text());
header_editor->deleteLater(); //safely delete editor
header_editor = 0;
}
return false;
}
Downsides of this method are that it's hacky, things go bad when headers are resized or table is scrolled. It's just an example that can be improved.
I have a feeling there has to be a simpler way. But Qt headers ignore Qt::ItemIsEditable flag and can't use delegates.
I can't figure out how I can move a slider handle of a QSlider in QT. When I press for example A( I want to move coursor left) and D(I want move coursor right) so I did
(void) new QShortcut(Qt::Key_A, this, SLOT(moveTickmarkLeft()));
(void) new QShortcut(Qt::Key_D, this, SLOT(moveTickmarkRight()));
implementation:
void LCDRange::moveTickmarkLeft()
{
slider->setSliderPosition(slider->sliderPosition - 1);
}
void LCDRange::moveTickmarkRight()
{
slider->setSliderPosition(slider->sliderPosition + 1);
}
the same I did using function setTickPosition(), what is the difference between setSliderPosition() and setTickPosition() how can I implement my idea, thanx in advance for any help
I believe using setSliderPosition method is the correct way of moving your slider in code. setTickPosition set the way how the tick mark should be drawn, so I guess, this is not smth you need. As for intercepting keyboard events: you can install an event filter to your form ui controls and put your slider moving logic there. Below is an example. More details on event filter here
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// install event filter to ui controls of the window
ui->textEdit->installEventFilter(this);
ui->pushButton->installEventFilter(this);
ui->horizontalSlider->installEventFilter(this);
}
// event filter implementation
bool MainWindow::eventFilter(QObject* watched, QEvent* event)
{
if (event->type() == QEvent::KeyPress )
{
QKeyEvent* keyEvent = (QKeyEvent*)event;
if (keyEvent->key()=='A')
{
qDebug() << "move slider";
ui->horizontalSlider->setSliderPosition(ui->horizontalSlider->sliderPosition()+1);
}
else if (keyEvent->key()=='B')
{
qDebug() << "move slider";
ui->horizontalSlider->setSliderPosition(ui->horizontalSlider->sliderPosition()-1);
}
}
return QMainWindow::eventFilter(watched, event);
}
hope this helps, regards
I have a console input in my Qt based application, it's a QLineEdit, all Ui is designed via QtDesigner. Is it any easy way way to handle up and down arrows in order to implement input history? The 'go to slot' only show returnProcessed signal, no way i can see to handle up and down arrows :(
you can install event filter and watch your line edit event in your window class. Below is an example:
declare event handler method on your window class:
class MainWindow : public QMainWindow {
Q_OBJECT
...
protected:
void changeEvent(QEvent *e);
...
};
window constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
...
ui->lineEdit->installEventFilter(this);
}
event handler implementation:
bool MainWindow::eventFilter(QObject* obj, QEvent *event)
{
if (obj == ui->lineEdit)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Up)
{
qDebug() << "lineEdit -> Qt::Key_Up";
return true;
}
else if(keyEvent->key() == Qt::Key_Down)
{
qDebug() << "lineEdit -> Qt::Key_Down";
return true;
}
}
return false;
}
return QMainWindow::eventFilter(obj, event);
}
hope this helps, regards
You can subclass QLineEdit and re-implement the virtual keyPressEvent method to handle your special keys.
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Up){
// move back in history
}
else if(event->key() == Qt::Key_Down){
// move forward in history
}
else{
// default handler for event
QLineEdit::keyPressEvent(event);
}
}
I had the same problem, but I find out in other forums that you need to setFocus, e.g.:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
...
ui->lineEdit->installEventFilter(this);
this->setFocus();
}
It works for me.
Reference:
http://www.qtforum.org/article/28240/how-to-get-arrow-keys.html
For me in PyQt this was not working,
class MainWidget(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi()
self->installEventFilter(self)
But this worked,
class MainWidget(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi()
QtGui.QApplication.instance().installEventFilter(self)