I am trying to tweak the ui of a QComboBox in a way that the user can remove items from the drop down list (without first selecting them).
The background is that I am using the QComboBox to indicate which data file is open right now. I am also using it as a cache for recently opened files. I would like the user to be able to remove entries he does not want to have listed anymore. This could be either by just hitting the delete key, or a context menu, or whatever is straightforward to implement. I do not want to rely on selecting the item first. A similar behavior can be found in Firefox, where old cached suggestions for an entry filed can be deleted.
I was considering subclassing the list view used by QComboBox, however, I did not find enough documentation to get me started.
I would be grateful for any hints and suggestions. I am using PyQt, but have no problems with C++ samples.
I solved this problem using code from the installEventFilter documentation.
//must be in a header, otherwise moc gets confused with missing vtable
class DeleteHighlightedItemWhenShiftDelPressedEventFilter : public QObject
{
Q_OBJECT
protected:
bool eventFilter(QObject *obj, QEvent *event);
};
bool DeleteHighlightedItemWhenShiftDelPressedEventFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key::Key_Delete && keyEvent->modifiers() == Qt::ShiftModifier)
{
auto combobox = dynamic_cast<QComboBox *>(obj);
if (combobox){
combobox->removeItem(combobox->currentIndex());
return true;
}
}
}
// standard event processing
return QObject::eventFilter(obj, event);
}
myQComboBox->installEventFilter(new DeleteHighlightedItemWhenShiftDelPressedEventFilter);
comboBox->removeItem(int index) // removes item at index
You can use a specialized class that automates processes, therefore it saves time in the end.
For example, there's a class named KrHistoryComboBox (which inherits from the KHistoryComboBox class) that is used in the program named Krusader.
Although this time, for this answer: the following code is a version that inherits directly from a QComboBox (though a QComboBox can not do as many things as a KHistoryComboBox), and one example of its use:
File main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
File mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
File mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "krhistorcombobox.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Creates a new editable comboBox, and populates it with data
KrHistorComboBox *combox;
combox = new KrHistorComboBox(this);
combox->setEditable(true);
QStringList elementsToAdd = {"one", "two", "three", "four", "five", "six"};
combox->insertItems(0, elementsToAdd);
}
MainWindow::~MainWindow()
{
delete ui;
}
File krhistorcombobox.h
/*****************************************************************************
* Copyright (C) 2018-2019 Shie Erlich <krusader#users.sourceforge.net> *
* Copyright (C) 2018-2019 Rafi Yanai <krusader#users.sourceforge.net> *
* Copyright (C) 2018-2019 Krusader Krew [https://krusader.org] *
* *
* This file is part of Krusader [https://krusader.org]. *
* *
* Krusader is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* Krusader is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with Krusader. If not, see [http://www.gnu.org/licenses/]. *
*****************************************************************************/
#ifndef KRHISTORCOMBOBOX_H
#define KRHISTORCOMBOBOX_H
// QtWidgets
#include <QComboBox>
/**
* A specialized version of a QComboBox, e.g. it deletes the current
* item when the user presses Shift+Del
*/
class KrHistorComboBox : public QComboBox
{
Q_OBJECT
public:
explicit KrHistorComboBox(QWidget *parent = nullptr);
};
#endif // KRHISTORCOMBOBOX_H
File krhistorcombobox.cpp
/*****************************************************************************
* Copyright (C) 2018-2019 Shie Erlich <krusader#users.sourceforge.net> *
* Copyright (C) 2018-2019 Rafi Yanai <krusader#users.sourceforge.net> *
* Copyright (C) 2018-2019 Krusader Krew [https://krusader.org] *
* *
* This file is part of Krusader [https://krusader.org]. *
* *
* Krusader is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* Krusader is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with Krusader. If not, see [http://www.gnu.org/licenses/]. *
*****************************************************************************/
#include "krhistorcombobox.h"
// QtCore
#include <QEvent>
// QtGui
#include <QKeyEvent>
// QtWidgets
#include <QAbstractItemView>
/**
* A KrHistorComboBox event filter that e.g. deletes the current item when Shift+Del is pressed
* There was more information in https://doc.qt.io/qt-5/qobject.html#installEventFilter,
* https://forum.qt.io/post/160618 and
* https://stackoverflow.com/questions/17820947/remove-items-from-qcombobox-from-ui/52459337#52459337
*/
class KHBoxEventFilter : public QObject
{
Q_OBJECT
public:
explicit KHBoxEventFilter(QObject *parent = nullptr) : QObject(parent) {}
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};
bool KHBoxEventFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
auto keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->modifiers() == Qt::ShiftModifier && keyEvent->key() == Qt::Key::Key_Delete) {
auto comboBox = qobject_cast<QComboBox *>(obj);
if (comboBox != nullptr) {
// Delete the current item
comboBox->removeItem(comboBox->currentIndex());
return true;
}
}
}
// Perform the usual event processing
return QObject::eventFilter(obj, event);
}
/**
* An event filter for the popup list of a KrHistorComboBox, e.g. it deletes the current
* item when the user presses Shift+Del
*/
class KHBoxListEventFilter : public QObject
{
Q_OBJECT
public:
explicit KHBoxListEventFilter(QObject *parent = nullptr) : QObject(parent) {}
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};
bool KHBoxListEventFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
auto keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->modifiers() == Qt::ShiftModifier && keyEvent->key() == Qt::Key::Key_Delete) {
auto itemView = qobject_cast<QAbstractItemView *>(obj);
if (itemView->model() != nullptr) {
// Delete the current item from the popup list
itemView->model()->removeRow(itemView->currentIndex().row());
return true;
}
}
}
// Perform the usual event processing
return QObject::eventFilter(obj, event);
}
#include "krhistorcombobox.moc" // required for class definitions with Q_OBJECT macro in implementation files
KrHistorComboBox::KrHistorComboBox(QWidget *parent): QComboBox(parent)
{
installEventFilter(new KHBoxEventFilter(this));
QAbstractItemView *itemView = view();
if (itemView != nullptr)
itemView->installEventFilter(new KHBoxListEventFilter(this));
}
File krexample.pro
#-------------------------------------------------
#
# Project created by QtCreator 2018-09-22T18:33:23
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = untitled
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
krhistorcombobox.cpp \
mainwindow.cpp
HEADERS += \
krhistorcombobox.h \
mainwindow.h
FORMS += \
mainwindow.ui
File mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle" >
<string>MainWindow</string>
</property>
<widget class="QMenuBar" name="menuBar" />
<widget class="QToolBar" name="mainToolBar" />
<widget class="QWidget" name="centralWidget" />
<widget class="QStatusBar" name="statusBar" />
</widget>
<layoutDefault spacing="6" margin="11" />
<pixmapfunction></pixmapfunction>
<resources/>
<connections/>
</ui>
This is a screenshot of the example program being executed, before pressing Shift+Del (which would remove the option named "two"):
Note: Some source code in the present answer is based on https://doc.qt.io/qt-5/qobject.html#installEventFilter, https://forum.qt.io/post/160618 and the good work by the user named "nwp" in https://stackoverflow.com/a/26976984 (although that answer does not include code to delete an element of the popup list if the popup list is being seen, and it has a "memory leak" (an object is constructed but not destroyed) therefore if a developer adds a destructor like e.g. ~DeleteHighlightedItemWhenShiftDelPressedEventFilter() { QTextStream(stdout) << "DESTRUCTED" << endl; } the developer later sees that the code of the destructor is never executed, and so there are memory leaks; currently I haven't got stackoverflow points in order to add a comment in https://stackoverflow.com/a/26976984).
Sorry for being that late to this thread, but I'd like to contribute some other methods I found, just in case that someone else is looking for it like me. The methods have been tested with Qt 5.6. I cannot guarantee that they will work in other versions.
One possibility is to listen to the "pressed()" signal of the QCombobox' view(). That way we could use the right mouse button to remove items from the list. I was surprised to see that the view() is always available, never NULL, and that items can be deleted while it is displayed, so the following works quite well:
class MyCombobox : public QComboBox
{
Q_OBJECT
public: MyCombobox(QWidget *pParent = NULL);
protected slots: void itemMouseDown(const QModelIndex &pIndex);
};
MyCombobox::MyCombobox(QWidget *pParent)
{
connect( QComboBox::view(), SIGNAL(pressed(const QModelIndex &)),
this, SLOT(itemMouseDown(const QModelIndex &)) );
}
void MyCombobox::itemMouseDown(const QModelIndex &pIndex)
{
if( QApplication::mouseButtons() == Qt::RightButton )
{
QComboBox::model()->removeRow(pIndex.row());
}
}
A second option is to install an event filter, but also into the view. That way we can use the delete key or anything else to remove items. It might be a good idea to test for NULL pointers and invalid row indices, but I omitted that for clarity.
class MyCombobox : public QComboBox
{
Q_OBJECT
public: MyCombobox(QWidget *pParent = NULL);
protected: bool eventFilter(QObject *pWatched, QEvent *pEvent);
};
MyCombobox::MyCombobox(QWidget *pParent)
{
QComboBox::view()->installEventFilter(this);
}
bool MyCombobox::eventFilter(QObject *pWatched, QEvent *pEvent)
{
if( pEvent->type() == QEvent::KeyPress )
{
QKeyEvent *tKeyEvent = static_cast<QKeyEvent*>(pEvent);
if( tKeyEvent->key() == Qt::Key_Delete )
{
QComboBox::model()->removeRow(QComboBox::view()->currentIndex().row());
return true;
}
}
return QObject::eventFilter(pWatched, pEvent);
}
That's it.
You can delete the active selected value of a QComboBox by:
ui->comboBox->removeItem(ui->comboBox->currentIndex());
If you could live with selecting the entry first,
and could accept a "Remove" button besides the combobox,
you could extend QComboBox with a suitable slot.
class IQComboBox : public QComboBox
{
Q_OBJECT
public :
IQComboBox(QWidget *parent = nullptr) : QComboBox(parent) {}
public slots :
void remove_current_item(void) { removeItem(currentIndex()); }
};
Then connect the button's "released" signal with the new slot.
IQComboBox combo;
QPushButton remove_button(tr("Remove"));
remove_button.setToolTip(tr("Remove the current item from the list."));
connect(&remove_button, SIGNAL(released()),
&combo, SLOT(remove_current_item()));
Related
I wanted to create an aircraft altitude indicator and embed it in PyQt5.
I found a GitHub repository that has custom Altitude indicator built using cpp. Below is the link to the github repo.
https://github.com/marek-cel/QFlightinstruments
There is a video tutorial included at the end. I followed the exact steps he followed. But when I ran it, I got the following error.
"In file included from ..\Instruments\qfi\qfi_AI.cpp:23:
../Instruments/qfi/qfi_AI.h:28:10:fatal error: QGraphicsSvgItem: No such file or directory"
The same error is showing for qfi_EADI.h, qfi_EHSI.h and qfi_HI.h as well.
I have included the header files and added the following line to my .pro file
QT += core gui svg
Below is my qfi_AI.h file (the .h and cpp file can be found in github)
#ifndef QFI_AI_H
#define QFI_AI_H
////////////////////////////////////////////////////////////////////////////////
#include <QGraphicsView>
#include <QGraphicsSvgItem> //error
////////////////////////////////////////////////////////////////////////////////
/**
* #brief Attitude Indicator widget class.
*/
class qfi_AI : public QGraphicsView
{
Q_OBJECT
public:
/** Constructor. */
explicit qfi_AI( QWidget *parent = Q_NULLPTR );
/** Destructor. */
virtual ~qfi_AI();
/** Reinitiates widget. */
void reinit();
/** Refreshes (redraws) widget. */
void redraw();
/** #param roll angle [deg] */
void setRoll( double roll );
/** #param pitch angle [deg] */
void setPitch( double pitch );
protected:
/** */
void resizeEvent( QResizeEvent *event );
private:
QGraphicsScene *_scene;
QGraphicsSvgItem *_itemBack;
QGraphicsSvgItem *_itemFace;
QGraphicsSvgItem *_itemRing;
QGraphicsSvgItem *_itemCase;
double _roll;
double _pitch;
double _faceDeltaX_new;
double _faceDeltaX_old;
double _faceDeltaY_new;
double _faceDeltaY_old;
double _scaleX;
double _scaleY;
const int _originalHeight;
const int _originalWidth;
const double _originalPixPerDeg;
QPointF _originalAdiCtr;
const int _backZ;
const int _faceZ;
const int _ringZ;
const int _caseZ;
void init();
void reset();
void updateView();
};
////////////////////////////////////////////////////////////////////////////////
#endif //QFI_AI_H
How do I resolve this issue?
In Qt6 many submodules have been restructured, for example the QGraphicsSvgItem and QSvgWidget classes were moved to a new submodule called svgwidgets so that the svg submodule no longer depends on the widgets submodule which improves memory in applications that do not need widgets.
So the solution is to add:
QT += svgwidgets
That is clearly indicated in the docs:
The QGraphicsSvgItem inherits QGraphicsObject, which requires widgets to be included. So, include QT += widgets in your .pro file.
I'm new in Qt and have a question.
I have QLabel and QLineEdit objects, and when QLabel text is clicked on, I want to set this text in QLineEdit.
Also I have read that QLabel has not clicked signal.
Can you explain how can I do this and write code for me ?!
Either style another type of QWidget such as a specific QPushButton to look like a QLabel and use its clicked() signal or inherit QLabel yourself and emit your own clicked() signal.
See this example:
https://wiki.qt.io/Clickable_QLabel
If you choose the latter option you can pass the text in the signal. Then connect the necessary signals/slots up between the QLabel and the QLineEdit like so:
QObject::connect(&label, SIGNAL(clicked(const QString& text)),
&lineEdit, SLOT(setText(const QString& text)));
A simple way to accomplish that, without a need for any subclassing, is a signal source that monitors the events on some object and emits relevant signals:
// main.cpp - this is a single-file example
#include <QtWidgets>
class MouseButtonSignaler : public QObject {
Q_OBJECT
bool eventFilter(QObject * obj, QEvent * ev) Q_DECL_OVERRIDE {
if ((ev->type() == QEvent::MouseButtonPress
|| ev->type() == QEvent::MouseButtonRelease
|| ev->type() == QEvent::MouseButtonDblClick)
&& obj->isWidgetType())
emit mouseButtonEvent(static_cast<QWidget*>(obj),
static_cast<QMouseEvent*>(ev));
return false;
}
public:
Q_SIGNAL void mouseButtonEvent(QWidget *, QMouseEvent *);
MouseButtonSignaler(QObject * parent = 0) : QObject(parent) {}
void installOn(QWidget * widget) {
widget->installEventFilter(this);
}
};
The emit keyword is an empty macro, Qt defines it as follows:
#define emit
It is for use by humans as a documentation aid prefix only, the compiler and moc ignore it. As a documentation aid, it means: the following method call is a signal emission. The signals are simply methods whose implementation is generated for you by moc - that's why we have to #include "main.moc" below to include all the implementations that moc has generated for the object class(es) in this file. There's otherwise nothing special or magical to a signal. In this example, you could look in the build folder for a file called main.moc and see the implementation (definition) of void MouseButtonSignaler::mouseButtonEvent( .. ).
You can then install such a signaler on any number of widgets, such as a QLabel:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MouseButtonSignaler signaler;
QWidget w;
QVBoxLayout layout(&w);
QLabel label("text");
QLineEdit edit;
layout.addWidget(&label);
layout.addWidget(&edit);
signaler.installOn(&label);
QObject::connect(&signaler, &MouseButtonSignaler::mouseButtonEvent,
[&label, &edit](QWidget*, QMouseEvent * event) {
if (event->type() == QEvent::MouseButtonPress)
edit.setText(label.text());
});
w.show();
return app.exec();
}
#include "main.moc"
You need to create one Custom Label class, which will inherit QLabel. Then you can use MouseButtonRelease event to check clicking of Label and emit your custom signal and catch in one SLOT.
Your .h file will be as below:
class YourLabelClass : public QLabel{
signals:
void myLabelClicked(); // Signal to emit
public slots:
void slotLabelClicked(); // Slot which will consume signal
protected:
bool event(QEvent *myEvent); // This method will give all kind of events on Label Widget
};
In your .cpp file, your constructor will connect signal & slot as below :
YourLabelClass :: YourLabelClass(QWidget* parent) : QLabel(parent) {
connect(this, SIGNAL(myLabelClicked()), this, SLOT(slotLabelClicked()));
}
Remaining event method and SLOT method will be implemented as below:
bool YourLabelClass :: event(QEvent *myEvent)
{
switch(myEvent->type())
{
case(QEvent :: MouseButtonRelease): // Identify Mouse press Event
{
qDebug() << "Got Mouse Event";
emit myLabelClicked();
break;
}
}
return QWidget::event(myEvent);
}
void YourLabelClass :: slotLabelClicked() // Implementation of Slot which will consume signal
{
qDebug() << "Clicked Label";
}
For Changing a Text on QLineEdit, you need to create a Custom Class and share object pointer with custom QLabel Class. Please check test code at this link
In the above example the header needs Q_OBJECT:
class YourLabelClass : public QLabel{
Q_OBJECT
signals:
I'm creating a simple virtual keyboard in a QDockWidget...
When the widget is docked into the QMainWindow, the selected widget (for example a qdoublespinbox) is highlighted and if I click on the virtual keyboard clearFocus() works...
When the QDockWidget is floating above the window and I click a button, clearFocus doesn't work and I can't see the focused widget in QMainWindow...
How can I force the QDockWidget to not have any focus at all?
Thanks :-)
This is the code:
// class MyVirtualKeyboard : public QDockWidget
void MyVirtualKeyboard::sendKey(Qt::Key key, Qt::KeyboardModifier mod)
{
this->clearFocus();
QMainWindow *w = dynamic_cast<QMainWindow *>(this->parent());
if(w == NULL) return;
QWidget *widget = w->focusWidget();
QString repr = QKeySequence(key).toString();
QKeyEvent *pressEvent = new QKeyEvent(QEvent::KeyPress, key, mod, repr);
QKeyEvent *releaseEvent = new QKeyEvent(QEvent::KeyRelease, key, mod, repr);
qDebug("%s", pressEvent->text().toAscii().data());
MyApplication *app = MyApplication::myInstance();
app->postEvent(widget, pressEvent);
app->postEvent(widget, releaseEvent);
}
void MyVirtualKeyboard::on_BTN_1_clicked()
{
sendKey(Qt::Key_1);
}
...
The clearFocus() call should be unnecessary. Your dock widget and all of its widgets must have the Qt::NoFocus policy.
The code below shows how you might do it.
// https://github.com/KubaO/stackoverflown/tree/master/questions/vkb-focus-18558664
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class Keyboard : public QDockWidget {
Q_OBJECT
QWidget m_widget;
QGridLayout m_layout{&m_widget};
QToolButton m_buttons[10];
void sendKey(Qt::Key key, Qt::KeyboardModifier mod)
{
if (! parentWidget()) return;
auto target = parentWidget()->focusWidget();
if (! target) return;
auto repr = QKeySequence(key).toString();
auto pressEvent = new QKeyEvent(QEvent::KeyPress, key, mod, repr);
auto releaseEvent = new QKeyEvent(QEvent::KeyRelease, key, mod, repr);
qApp->postEvent(target, pressEvent);
qApp->postEvent(target, releaseEvent);
qDebug() << repr;
}
Q_SLOT void clicked() {
auto key = sender()->property("key");
if (key.isValid()) sendKey((Qt::Key)key.toInt(), Qt::NoModifier);
}
public:
explicit Keyboard(const QString & title, QWidget *parent = nullptr) : Keyboard(parent) {
setWindowTitle(title);
}
explicit Keyboard(QWidget *parent = nullptr) : QDockWidget(parent) {
int i{};
for (auto & btn : m_buttons) {
btn.setText(QString::number(i));
btn.setProperty("key", Qt::Key_0 + i);
m_layout.addWidget(&btn, 0, i, 1, 1);
connect(&btn, SIGNAL(clicked()), SLOT(clicked()));
btn.setFocusPolicy(Qt::NoFocus);
++i;
}
setWidget(&m_widget);
setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
}
};
int main(int argc, char ** argv)
{
QApplication a(argc, argv);
QMainWindow w;
w.setCentralWidget(new QLineEdit);
w.addDockWidget(Qt::TopDockWidgetArea, new Keyboard("Keyboard", &w));
w.show();
return a.exec();
}
#include "main.moc"
You can prevent a widget from taking focus by setting QWidget::focusPolicy = Qt::NoFocus.
However, there are two concepts here that you're mixing - the focused control (per window), and the active window (per desktop). I think in the scenario you're describing (a torn-off popup window), the OS window manager is likely to still change the active top-level window even if Qt doesn't set a focused control. That will result in nobody having keyboard focus (which is a valid state!).
So I think a full answer to your question will involve some non-portable bits. I don't know what GUI environment you're working in, but I know some of the answer for Win32, so I'll keep going and hope that's useful:
Win32
There's a pretty good discussion of the state tracking for Win32 on MSDN in the article Win32 Activation and Focus. I'm not aware that Qt does anything to wrap this level, so you'd have to use QWidget::nativeEvent or QCoreApplication::installNativeEventFilter to get at the low-level event. If you can subclass the window, I'd prefer the former, since it's more self-contained.
bool FooWidget::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
#ifdef Q_OS_WIN
if(eventType == "windows_generic_MSG") {
const MSG *msg = reinterpret_cast<MSG *>(message);
if(msg->message == WM_MOUSEACTIVATE) {
*result = MA_NOACTIVATE;
return true;
}
}
#else
#error Need platform-specific code to suppress click-activation
#endif
return false;
}
This should block the click from activating the window (MA_NOACTIVATE), and block Qt from processing it further (return true), while leaving other all events (including the the click, since we didn't use MA_NOACTIVATEANDEAT to block it too) to be processed into QEvents and Qt signals normally (return false at the end).
If you need further low-level access (though I don't think you will), see also QWidget::effectiveWinId() and QWidget::windowHandle
Thanks a lot to Martin Gräßlin for the answer!
My recommendation: check out the virtual keyboard code in KDE Plasma: http://quickgit.kde.org/?p=kdeplasma-addons.git&a=blob&h=5628d6325afe57f85917dad865a07d4116335726&hb=a658d1e257cfca2a43c12714d026ec26f1fdb755&f=applets%2Fplasmaboard%2Fwidget.cpp
Looks like the key is setWindowFlags(Qt::X11BypassWindowManagerHint) and setFocusPolicy(Qt::NoFocus)
MyVirtualKeyboard::MyVirtualKeyboard(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::MyVirtualKeyboard)
{
ui->setupUi(this);
this->connect(this, SIGNAL(topLevelChanged(bool)), this, SLOT(topLevelChanged()));
}
void MyVirtualKeyboard::topLevelChanged()
{
if(this->isWindow())
{
this->setWindowFlags(Qt::Popup | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
this->setFocusPolicy(Qt::NoFocus);
this->show();
}
}
I think I've found a better way to do it!
Just use this->setAttribute(Qt::WA_X11DoNotAcceptFocus); and voila!
Example:
MyVirtualKeyboard::MyVirtualKeyboard(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::MyVirtualKeyboard)
{
ui->setupUi(this);
this->setAttribute(Qt::WA_X11DoNotAcceptFocus);
}
I am working with Qt application in which I want to create a QListWidget with names of all application installed on device and its icon.
So I was unable get all application names and UID of each application from the code in this LINK.
But I was also unable to get the application icons. I tried both this LINK1 & LINK2 but here I came across few more issues like how to convert CGulIcon into QIcon & CApaMaskedBitmap into QIcon.
How can I do this?
If you are unable to get the solution or have any more doubts click here for disscussion.
main.cpp
#include "GetInstalledApps.h"
#include <QtGui>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GetInstalledApps w;
w.showMaximized();
return a.exec();
}
.pro
TEMPLATE = app
TARGET = GetInstalledApps
QT += core \
gui
HEADERS += GetInstalledApps.h
SOURCES += main.cpp \
GetInstalledApps.cpp
FORMS += GetInstalledApps.ui
RESOURCES +=
HEADERS += xqinstaller_p.h \
xqinstaller.h \
SOURCES += xqinstaller_p.cpp \
xqinstaller.cpp
symbian:LIBS += -lswinstcli \
-lcommdb \
-lapparc \
-lefsrv \
-lapgrfx \
symbian:TARGET.CAPABILITY += TrustedUI
symbian:TARGET.UID3 = 0xEF3055F4
GetInstalledApps.h
#ifndef GETINSTALLEDAPPS_H
#define GETINSTALLEDAPPS_H
#include <QtGui/QMainWindow>
#include "ui_GetInstalledApps.h"
#include "xqinstaller.h"
class GetInstalledApps : public QMainWindow
{
Q_OBJECT
public:
GetInstalledApps(QWidget *parent = 0);
~GetInstalledApps();
private:
void GetApps();
private:
Ui::GetInstalledAppsClass ui;
XQInstaller* m_installer;
QMap<QString, uint> m_applications;
QList<QString> m_appNames;
QList<uint> m_appUID;
};
#endif // GETINSTALLEDAPPS_H
GetInstalledApps.cpp
#include "GetInstalledApps.h"
#include <QScrollArea>
GetInstalledApps::GetInstalledApps(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
setWindowTitle("GetAllInstalledApps");
m_installer = new XQInstaller(this);
GetApps();
}
void GetInstalledApps::GetApps()
{
/* Get List of applications.
* type of m_applications is QMap<QString, uint>.
* type of m_installer is XQInstaller
*/
m_applications = m_installer->applications();
/* Get List of application names
type of m_appNames is QList<QString> */
m_appNames = m_applications.keys();
/* Get List of application UID in decimal.
type of m_appUID is QList<uint> */
m_appUID = m_applications.values();
ui.listWidget->clear();
for (int i = 0; i < m_appNames.count(); i++)
{
QString str;
/* convert UID from decimal to hex and then string. */
str.setNum(m_appUID.at(i),16);
/* append name and UID to string */
QString string(m_appNames.at(i)+" UID:"+ str);
/* append string to list widget to display on screen */
ui.listWidget->addItem(string);
}
/* Let's make the UI scale so that we can scroll it. */
QScrollArea* scrollArea = new QScrollArea;
scrollArea->setWidget(ui.listWidget);
scrollArea->setWidgetResizable(true);
setCentralWidget(scrollArea);
}
GetInstalledApps::~GetInstalledApps()
{
}
xqinstaller.h
#ifndef XQINSTALLER_H
#define XQINSTALLER_H
// INCLUDES
#include <QObject>
#include <QMap>
class XQInstallerPrivate;
// CLASS DECLARATION
class XQInstaller : public QObject
{
Q_OBJECT
public:
enum Error {
NoError = 0,
OutOfMemoryError,
AlreadyInUseError,
UserCancelError,
PackageNotSupportedError,
SecurityFailureError,
MissingDependencyError,
NoRightsError,
BusyError,
AccessDeniedError,
UpgradeError,
UnknownError = -1
};
enum Drive {
DriveA, DriveB, DriveC, DriveD, DriveE,
DriveF, DriveG, DriveH, DriveI, DriveJ,
DriveK, DriveL, DriveM, DriveN, DriveO,
DriveP, DriveQ, DriveR, DriveS, DriveT,
DriveU, DriveV, DriveW, DriveX, DriveY,
DriveZ
};
XQInstaller(QObject *parent = 0);
~XQInstaller();
bool install(const QString& file, XQInstaller::Drive drive = XQInstaller::DriveC);
QMap<QString, uint> applications() const;
bool remove(uint uid);
XQInstaller::Error error() const;
Q_SIGNALS:
void applicationInstalled();
void applicationRemoved();
void error(XQInstaller::Error);
private:
friend class XQInstallerPrivate;
XQInstallerPrivate *d;
};
#endif // XQINSTALLER_H
xqinstaller.cpp
#include "xqinstaller.h"
#include "xqinstaller_p.h"
/*!
\class XQInstaller
\brief The XQInstaller class is used to install sis-packages silently.
This extension can be used for example to install back-end applications.
Example:
\code
XQInstaller *installer = new XQInstaller(this);
QMap<QString, uint> applications = installer->applications();
QListWidget *applicationList = new QListWidget(this);
QList<QString> appNames = applications.keys();
for (int i = 0; i < appNames.count(); i++) {
applicationList->addItem(appNames.at(i));
}
\endcode
*/
/*!
Constructs a XQInstaller object with the given parent.
\sa install(), remove()
*/
XQInstaller::XQInstaller(QObject *parent)
: QObject(parent), d(new XQInstallerPrivate(this))
{
}
/*!
Destroys the XQInstaller object.
*/
XQInstaller::~XQInstaller()
{
delete d;
}
/*!
Installs a sis package silently given as parameter.
\param file Sis package
\param drive Drive letter where the sis is installed to. Default value is 'C'.
\return If false is returned, an error has occurred. Call error() to get a value of
XQInstaller::Error that indicates which error occurred
\sa error()
*/
bool XQInstaller::install(const QString& file, XQInstaller::Drive drive)
{
return d->install(file, drive);
}
/*!
Get list of installed applications
If an empty QMap is returned, an error has possibly occurred. Call error() to get a value of
XQInstaller::Error that indicates which error occurred if any
\return List of installed applications
\sa error()
*/
QMap<QString, uint> XQInstaller::applications() const
{
return d->applications();
}
/*!
Removes application specified by the uid
\param uid of the application
\return True if removing was successfully started, otherwise false
\sa error()
*/
bool XQInstaller::remove(uint uid)
{
return d->remove(uid);
}
/*!
\enum XQInstaller::Error
This enum defines the possible errors for a XQInstaller object.
*/
/*! \var XQInstaller::Error XQInstaller::NoError
No error occured.
*/
/*! \var XQInstaller::Error XQInstaller::OutOfMemoryError
Not enough memory.
*/
/*! \var XQInstaller::Error XQInstaller::AlreadyInUseError
Installer is already in used.
*/
/*! \var XQInstaller::Error XQInstaller::UserCancelError
Installer cancelled by the user.
*/
/*! \var XQInstaller::Error XQInstaller::PackageNotSupportedError
Package not supported
*/
/*! \var XQInstaller::Error XQInstaller::SecurityFailureError
Security failure
*/
/*! \var XQInstaller::Error XQInstaller::MissingDependencyError
Missing dependency
*/
/*! \var XQInstaller::Error XQInstaller::NoRightsError
No rights
*/
/*! \var XQInstaller::Error XQInstaller::BusyError
Installer is busy
*/
/*! \var XQInstaller::Error XQInstaller::AccessDeniedError
Access denied
*/
/*! \var XQInstaller::Error XQInstaller::UpgradeError
Error while upgrading
*/
/*! \var XQInstaller::Error XQInstaller::UnknownError
Unknown error.
*/
/*!
Returns the type of error that occurred if the latest function call failed; otherwise returns NoError
\return Error code
*/
XQInstaller::Error XQInstaller::error() const
{
return d->error();
}
/*!
\fn void XQInstaller::applicationInstalled()
This signal is emitted when the application has been installed.
\sa install()
*/
/*!
\fn void XQInstaller::error(XQInstaller::Error)
This signal is emitted if error occured during the asynchronous operation
\sa install()
*/
/*!
\fn void XQInstaller::applicationRemoved()
This signal is emitted when the application has been removed.
\sa remove()
*/
// End of file
xqinstaller_h.h
#ifndef XQINSTALLER_P_H
#define XQINSTALLER_P_H
// INCLUDES
#include "xqinstaller.h"
#include <SWInstApi.h>
#include <SWInstDefs.h>
// FORWARD DECLARATIONS
class QString;
class QFile;
// CLASS DECLARATION
class XQInstallerPrivate: public CActive
{
public:
enum State {
ERemove,
EInstall
};
XQInstallerPrivate(XQInstaller *installer);
~XQInstallerPrivate();
bool install(const QString& file, XQInstaller::Drive drive);
bool remove(uint uid);
QMap<QString, uint> applications() const;
public:
XQInstaller::Error error();
protected:
void DoCancel();
void RunL();
private:
XQInstaller *q;
mutable int iError;
SwiUI::RSWInstSilentLauncher iLauncher;
SwiUI::TInstallOptions iOptions;
SwiUI::TInstallOptionsPckg iOptionsPckg;
SwiUI::TUninstallOptions iUninstallOptions;
SwiUI::TUninstallOptionsPckg iUninstallOptionsPckg;
XQInstallerPrivate::State iState;
TFileName iFileName;
bool iLauncherConnected;
};
#endif /*XQINSTALLER_P_H*/
// End of file
xqinstaller_h.cpp
#include "xqinstaller.h"
#include "xqinstaller_p.h"
#include <f32file.h>
#include <apgcli.h>
XQInstallerPrivate::XQInstallerPrivate(XQInstaller *installer)
: CActive(EPriorityNormal), q(installer), iOptionsPckg(iOptions),
iUninstallOptionsPckg(iUninstallOptions), iLauncherConnected(false)
{
CActiveScheduler::Add(this);
}
XQInstallerPrivate::~XQInstallerPrivate()
{
Cancel();
if (iLauncherConnected) {
iLauncher.Close();
}
}
bool XQInstallerPrivate::install(const QString& file, XQInstaller::Drive drive)
{
int asciiValue = 10; // = 'A'
TRAP(iError,
if (!iLauncherConnected) {
User::LeaveIfError(iLauncher.Connect());
iLauncherConnected = true;
}
if (IsActive()) {
User::Leave(KErrInUse);
}
iState = XQInstallerPrivate::EInstall;
iOptions.iUpgrade = SwiUI::EPolicyAllowed;
iOptions.iOCSP = SwiUI::EPolicyNotAllowed;
iOptions.iDrive = TChar(asciiValue+drive);
iOptions.iUntrusted = SwiUI::EPolicyAllowed;
iOptions.iCapabilities = SwiUI::EPolicyAllowed;
iOptions.iOptionalItems = SwiUI::EPolicyAllowed;
iOptions.iOverwrite = SwiUI::EPolicyAllowed;
TPtrC16 fileName(reinterpret_cast<const TUint16*>(file.utf16()));
iFileName = fileName;
iLauncher.SilentInstall(iStatus, iFileName, iOptionsPckg);
SetActive();
)
return (iError == KErrNone);
}
bool XQInstallerPrivate::remove(uint uid)
{
TRAP(iError,
if (!iLauncherConnected) {
User::LeaveIfError(iLauncher.Connect());
iLauncherConnected = true;
}
if (IsActive()) {
User::Leave(KErrInUse);
}
iState = XQInstallerPrivate::ERemove;
iLauncher.SilentUninstall(iStatus,TUid::Uid(uid),
iUninstallOptionsPckg, SwiUI::KSisxMimeType);
SetActive();
)
return (iError == KErrNone);
}
QMap<QString, uint> XQInstallerPrivate::applications() const
{
RApaLsSession lsSession;
QMap<QString, uint> applications;
// Connect to application architecture server
TRAP(iError,
User::LeaveIfError(lsSession.Connect());
CleanupClosePushL(lsSession);
TApaAppInfo appInfo;
lsSession.GetAllApps();
while (lsSession.GetNextApp(appInfo) == KErrNone) {
TApaAppCapabilityBuf capability;
User::LeaveIfError(lsSession.GetAppCapability(capability,
appInfo.iUid));
if (appInfo.iCaption.Length() > 0 && !capability().iAppIsHidden) {
QString fullName = QString::fromUtf16(
appInfo.iCaption.Ptr(), appInfo.iCaption.Length());
applications.insert(fullName, (TUint)appInfo.iUid.iUid);
}
}
CleanupStack::PopAndDestroy(&lsSession);
)
return applications;
}
void XQInstallerPrivate::DoCancel()
{
if (iState == XQInstallerPrivate::EInstall) {
iLauncher.CancelAsyncRequest(SwiUI::ERequestSilentInstall);
} else if (iState == XQInstallerPrivate::ERemove) {
iLauncher.CancelAsyncRequest(SwiUI::ERequestSilentUninstall);
}
}
void XQInstallerPrivate::RunL()
{
if (iStatus.Int() == KErrNone) {
if (iState == XQInstallerPrivate::EInstall) {
emit q->applicationInstalled();
} else if (iState == XQInstallerPrivate::ERemove) {
emit q->applicationRemoved();
}
} else {
iError = iStatus.Int();
emit q->error(error());
}
}
XQInstaller::Error XQInstallerPrivate::error()
{
switch (iError) {
case KErrNone:
return XQInstaller::NoError;
case SwiUI::KSWInstErrInsufficientMemory:
case KErrNoMemory:
return XQInstaller::OutOfMemoryError;
case SwiUI::KSWInstErrFileInUse:
case KErrInUse:
return XQInstaller::AlreadyInUseError;
case SwiUI::KSWInstErrUserCancel:
return XQInstaller::UserCancelError;
case SwiUI::KSWInstErrPackageNotSupported:
return XQInstaller::PackageNotSupportedError;
case SwiUI::KSWInstErrSecurityFailure:
return XQInstaller::SecurityFailureError;
case SwiUI::KSWInstErrMissingDependency:
return XQInstaller::MissingDependencyError;
case SwiUI::KSWInstErrNoRights:
return XQInstaller::NoRightsError;
case SwiUI::KSWInstErrBusy:
return XQInstaller::BusyError;
case SwiUI::KSWInstErrAccessDenied:
return XQInstaller::AccessDeniedError;
case SwiUI::KSWInstUpgradeError:
return XQInstaller::UpgradeError;
case SwiUI::KSWInstErrGeneralError:
default:
return XQInstaller::UnknownError;
}
}
// End of file
And for getting QIcon::
Hearders Required:
#include <fbs.h> //CFbsBitmap
#include <aknsskininstance.h> //MAknsSkinInstance
#include <aknsutils.h> //AknsUtils
Library required:
LIBRARY fbscli.lib ///CFbsBitmap
LIBRARY aknskins.lib aknskinsrv.lib aknswallpaperutils.lib //MAknsSkinInstance ,AknsUtils
Source Code:
CGulIcon* CMyClass::GetApplicationIconL(const TUid& aAppUID)
{
CFbsBitmap* AppIcon(NULL);
CFbsBitmap* AppIconMsk(NULL);
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsUtils::CreateAppIconLC(skin,aAppUID, EAknsAppIconTypeContext,AppIcon,AppIconMsk);
CleanupStack::Pop(2);
return CGulIcon::NewL(AppIcon,AppIconMsk);
}
Well, for the icon thing look at this: CGullIcon there's a function that returns the Bitmap, a CFbsBitmap. Once you've done that look at this: http://qt-project.org/doc/qt-4.8/qpixmap.html#fromSymbianCFbsBitmap then you create a new QIcon(QPixmap) (QPixmap = the icon you've transformed). So most likely you're first passing it to a CFbsBitmap and then with QPixmap you use fromSymibnaCFbsBitmap().
CApaMaskedBitmap is a sub-class of CFbsBitmap if i'm not wrong, so it should work the same.
And for getting the applications and their UID try to look at this: http://www.developer.nokia.com/Community/Wiki/Get_list_of_installed_applications_and_its_UID_in_Qt
I use a QPlainTextEdit for a code editor that also shows line numbers.
But when I press shift+return a the editor makes a break, but the line number don't increases.
I think in html it would just be a <br/> instead of a new <p> tag...
Have a look at the screenshot...
You should probably be using QTextEdit since this is rich text we're talking about.
Override virtual void keyPressEvent ( QKeyEvent * e ). You can call QTextEdit::keyPressEvent in the implementation to delegate non-special cases.
You can, actually, use object with eventFilter and installEventFilter function.
#ifndef SHIFTENTERFILTER_H
#define SHIFTENTERFILTER_H
#include <QObject>
#include <QEvent>
#include <QKeyEvent>
class ShiftEnterFilter : public QObject
{
protected:
virtual bool eventFilter(QObject *, QEvent *event) {
if(event -> type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast <QKeyEvent> (event);
if((keyEvent -> modifiers() & Qt::ShiftModifier) && ((keyEvent -> key() == Qt::Key_Enter) || (keyEvent -> key() == Qt::Key_Return)))
return true;
}
return false;
}
public:
ShiftEnterFilter(QObject *parent = 0) : QObject(parent) {}
};
#endif
Just install this filter to your QPlainTextEdit
// code
ui -> plainTextEdit -> installEventFilter(new ShiftEnterFilter(this));
// code
Try this (CodeEdit inherits QPlainTextEdit):
/**
* override keyPressEvent, change behaviour of shift + enter(return)
* #brief CodeEdit::keyPressEvent
* #param event
*/
void CodeEdit::keyPressEvent(QKeyEvent *event)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
// disable shift + enter(return)
if ((keyEvent->modifiers() & Qt::ShiftModifier) && (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)) {
event->ignore();
return;
}
QPlainTextEdit::keyPressEvent(event);
}