How do I disable special handling of & on Qt button labels? - qt

I have inherited a virtual keyboard system with an array of buttons, one for each key. The label for each button is a single QChar. When showing the "symbols" keyboard, the code uses an '&' QChar for a key label, but the key shows as blank. I'm sure Qt is processing the '&' as a shortcut key prefix. Similarly, the entered text is shown on another, longer, button label; this label, as well, handles '&' character as an accelerator. Entering "ABC&DEF" is shown as "ABCDEF" with the 'D' underlined.
I have tried building with QT_NO_SHORTCUT #defined, but that made no difference.
Does anyone know of an easy way to disable this special handling of '&'?

The answer is found in Qt doc. QAbstractButton::text:
If the text contains an ampersand character ('&'), a shortcut is automatically created for it. The character that follows the '&' will be used as the shortcut key. Any previous shortcut will be overwritten or cleared if no shortcut is defined by the text. See the QShortcut documentation for details. To display an actual ampersand, use '&&'.
(Emphasize by me.)
QPushButton is derived from QAbstractButton inheriting this behavior.
Sample testQPushButtonAmp.cc:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QPushButton qBtn("Text with &&");
qBtn.show();
return app.exec();
}
testQPushButtonAmp.pro:
SOURCES = testQPushButtonAmp.cc
QT = widgets
Compiled and tested on cygwin64 on Windows 10:
$ qmake-qt5 testQPushButtonAmp.pro
$ make
$ ./testQPushButtonAmp
Qt Version: 5.9.4
Concerning how to disable this default behavior:
I had a look at woboq.org QAbstractButton::setText().
void QAbstractButton::setText(const QString &text)
{
Q_D(QAbstractButton);
if (d->text == text)
return;
d->text = text;
#ifndef QT_NO_SHORTCUT
QKeySequence newMnemonic = QKeySequence::mnemonic(text);
setShortcut(newMnemonic);
#endif
d->sizeHint = QSize();
update();
updateGeometry();
#ifndef QT_NO_ACCESSIBILITY
QAccessibleEvent event(this, QAccessible::NameChanged);
QAccessible::updateAccessibility(&event);
#endif
}
So, QT_NO_SHORTCUT disables to retrieve the shortcut out of text but it has to be defined when Qt library is built from source. Actually, I'm afraid even with disabled shortcuts, the single & will still become invisible in output.
I digged deeper in woboq.org and found some promising candidates e.g.:
qt_set_sequence_auto_menmonic()
Specifies whether mnemonics for menu items, labels, etc., should be honored or not. On Windows and X11, this feature is on by default; on macOS, it is off. When this feature is off (that is, when b is false), QKeySequence::mnemonic() always returns an empty string.
Note: This function is not declared in any of Qt's header files. To use it in your application, declare the function prototype before calling it.
and a sample in QProxyStyle
#include "textedit.h"
#include <QApplication>
#include <QProxyStyle>
class MyProxyStyle : public QProxyStyle
{
public:
int styleHint(StyleHint hint, const QStyleOption *option = 0,
const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const override
{
if (hint == QStyle::SH_UnderlineShortcut)
return 0;
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
};
int main(int argc, char **argv)
{
Q_INIT_RESOURCE(textedit);
QApplication a(argc, argv);
a.setStyle(new MyProxyStyle);
TextEdit mw;
mw.resize(700, 800);
mw.show();
//...
}
which I tried in my sample.
Finally, nothing of them achieved the desired effect, i.e. only "&&" was rendered as & but "&" never.
__

Related

Bring up virtual input plugin from QML

Searching for an alternative to Qt's official VirtualKeyboard I came across this MockupVirtualKeyboard repository. It is based on QPlatformInputContext. I build and installed the plugin to Qt5.15.2/plugins/platforminputcontexts, but I dont know how to bring the Virtual Keyboard up.
What I would like to achieve, using QML, is:
TextInput{
text: ""
onFocusChanged: showVirtualInput()
}
If you want to use the keyboard then you must set the environment variable "QT_IM_MODULE" to be "mockup", and you can do that by placing the following line of code in the main.cpp:
int main(int argc, char *argv[])
{
qputenv("QT_IM_MODULE", QByteArray("mockup"));
#if QT_VERSION &lt QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
# ...
On the other hand, you must change:
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface" FILE "mockup.json")
to
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface.5.1" FILE "mockup.json")
in the mockupplatforminputcontextplugin.h file, recompile and install the file so that it is compatible with Qt 5.15.2

Qt QFile / QTemporaryFile cannot read or write

I have no idea why, but i canĀ“t get the simplest example of QTemporaryFile to run... My real intent is to write data from QAudioInput into a temporary file before it is processed later.
After trying several times I realized that neither .read(), .readLine(), .readAll() or .write() would have any effect... The error string is always "Unknown Error" and it neither works for QFile or QTemporaryFile.
#include <QCoreApplication>
#include <QTemporaryFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTemporaryFile tf;
tf.open();
tf.write("Test");
QTextStream in(&tf);
qDebug() << "Testprogramm";
qDebug() << tf.isOpen();
qDebug() << tf.errorString();
qDebug() << in.readLine();
qDebug() << tf.readAll();
tf.close();
return a.exec();
}
The debug posts:
Testprogramm
true
"Unknown error"
""
""
Thank you in advance!
You need to move the file pointer back to the beginning of the file. This has to be done on the file itself when there's no stream on the file, or using the stream when one exists. Also - QFile is a proper C++ class that manages the file resource. There's no need to manually close the file. QFile::~QFile does that job.
The following works just fine:
#include <QtCore>
int main() {
auto line = QLatin1String("Test");
QTemporaryFile tf;
tf.open();
Q_ASSERT(tf.isOpen());
tf.write(line.data());
tf.reset(); // or tf.seek(0)
QTextStream in(&tf);
Q_ASSERT(in.readLine() == line);
in.seek(0); // not in.reset() nor tf.reset()!
Q_ASSERT(in.readLine() == line);
}
The above also demonstrates the following techniques applicable to sscce-style code:
Inclusion of entire Qt module(s). Remember that modules include their dependencies, i.e. #include <QtWidgets> is sufficient by itself.
Absence of main() arguments where unnecessary.
Absence of QCoreApplication instance where unnecessary. You will get clear runtime errors if you need the application instance but don't have one.
Use of asserts to indicate conditions that are expected to be true - that way you don't need to look at the output to verify that it is correct.
Use of QLatin1String over QStringLiteral where ASCII strings need to be compared to both C strings and QStrings. Implicit ASCII casts can be a source of bugs and are discouraged.
QLatin1String is a constant (read-only) wrapper, designed to wrap C string literals - thus there's no need to make line additionally const, although in real projects you'd want to follow the project's style guide here.

Why QMimeData is returning invalid QStringList at each call of member func formats()?

I was trying to use a for each [Modern c++ style] but the code is crashed each time!
It was something like :
for(auto &k:mimeData->formats())
{ ... }
And later out of my surprises I found that the QStringList returned by formats is either invalid or completely separate object though the internal data is ought to be same!
So I tried to figure out in more simple example :
#include <iostream>
#include <string>
#include <list>
#include <QCoreApplication>
#include <QMimeData>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<boolalpha;
list<string> ls;
cout<<(ls.begin() != ls.end())<<"\n";
QStringList qsl;
cout<<(qsl.begin() != qsl.end())<<"\n";
QMimeData qme;
cout<<(qme.formats().begin() != qme.formats().end())<<"\n";
cout<<"OMG! is it empty? -> "<<qme.formats().empty()<<"\n";
return a.exec();
}
The output is something like :
false
false
true
OMG! is it empty? -> true
Until or unless I take an rvalue reference I cant decide what is happening internally!
I really need a solution to use it with range based for loops, not Qt's foreach!
P.S. I dont want to copy it to avoid O(n).
Looking at the docs, there's no guarantee QMimeData class keeps QStringList of supported formats (http://doc.qt.io/qt-4.8/qmimedata.html#formats) as a field.
The source code supports that (Qt5.4/Src/qtbase/src/corelib/kernel/qmimedata.cpp:593):
QStringList QMimeData::formats() const
{
Q_D(const QMimeData);
QStringList list;
for (int i=0; i<d->dataList.size(); i++)
list += d->dataList.at(i).format;
return list;
}
Therefore this list is constructed on every call to formats(). Farther calls to it will always yield a separate container.
Since you do need to preserve it to traverse it, I'd recommend keeping a local copy of it. Do note that C++11 allows for it to be moved constructed (or in fact - optimized even better).

Qt: monitor global cursor click event with X11?

I want to capture global mouse click event in X11 , now
I tried to install a x11event filter , but it just doesn't work globally.
class XApplication: public QApplication
{
public:
XApplication (int & argc, char **argv):
QApplication (argc , argv)
{
}
protected:
bool x11EventFilter (XEvent *e)
{
qDebug() << "X11 Event: " << e->type;
return QApplication::x11EventFilter(e);
}
};
UPDATE
I mean outside the window , the code above works when I click on the window.
You can query X11 info from Qt using the QX11Info class. See its documentation. Then you can use raw Xlib from it.
You can use XGrabPointer(). If you use it, other apps won't receive the pointer events while the pointer is grabbed. man XGrabPointer will help you.
The "normal" way of subscribing for events is to use XSelectInput() on a window, but the problem is that you'll have to call XSelectInput on every single existing window. See its man page...
I know the xxf86dga extension has some calls related to mouse, but I'm not sure what they do.
XQueryPointer() is another way to query the pointer state without stealing events from other windows.
The only other place I can think of is the XInput extension, but I'm not sure it will help you either.
See the xev source code for a good reference on handling X11 events: http://cgit.freedesktop.org/xorg/app/xev
Sample code using XGrabPointer:
#include <stdio.h>
#include <assert.h>
#include <X11/Xlib.h>
int main(void)
{
Display *d;
Window root;
d = XOpenDisplay(NULL);
assert(d);
root = DefaultRootWindow(d);
XGrabPointer(d, root, False, ButtonPressMask | ButtonReleaseMask |
PointerMotionMask, GrabModeAsync, GrabModeAsync, None,
None, CurrentTime);
XEvent ev;
while (1) {
XNextEvent(d, &ev);
switch (ev.type) {
case ButtonPress:
printf("Button press event!\n");
break;
case ButtonRelease:
printf("Button release event!\n");
break;
case MotionNotify:
printf("Motion notify event!\n");
break;
default:
printf("Unknown event...\n");
}
}
XCloseDisplay(d);
return 0;
}
Compiled using: gcc x11mouse.c -o x11mouse -lX11

QDomElement::setTagName doesn't seem to work

The code
#include <QtCore>
#include <QtXml/QDomElement>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QDomElement* element = new QDomElement();
element->setTagName("feature");
qDebug() << element->tagName();
return app.exec();
}
prints simply "". However, as far as I can tell from the documentation it should print "feature". In fact
qDebug() << element->isNull();
prints true so something is not being set correctly. Does anyone know what I am doing wrong?
I'm using Qt 4.6.3 on openSUSE Linux 11.2.
You cannot use the default constructor. You need to use QDomDocument::createElement(const QString &tagName). The element needs to be part of a document. You cannot use it "standalone".
Here's what the documentation says for the QDomElement default constructor:
QDomElement::QDomElement ()
Constructs an empty element. Use the QDomDocument::createElement() function to construct elements with content.
By "empty" they mean null.

Resources