Cmd+Plus shortcut not recognised on MacBook - c++

I want to capture shortcut Cmd+Plus to do something (zoom something). But as I found this does not work on MacBooks because Cmd+Plus has to be pressed with holding Shift key. So instead of Cmd+Plus I got Cmd+Shift+=. What is interesting: on Windows and Linux everything works as expected (Ctrl instead of Cmd, of course).
A piece of code:
#include <QApplication>
#include <QDebug>
#include <QKeyEvent>
#include <QWidget>
class Widget : public QWidget
{
public:
void keyPressEvent(QKeyEvent *event) override {
qInfo() << event->key() << event->modifiers();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
When I press Cmd+Plus (with holding Shift), this code outputs 61 QFlags<Qt::KeyboardModifier>(ShiftModifier|ControlModifier) on my MacBook. Note that 61 is decadic number of '='.
This code outputs 43 QFlags<Qt::KeyboardModifier>(ShiftModifier|ControlModifier) on Windows and Linux notebooks which also require pressing Shift. But here 43 is '+'. Which is correct.
Well, how to capture Cmd+Plus then? On all platforms (equiv. Ctrl instead of Cmd on Windows and Linux), on all possible national keyboard layouts?

Related

how to translate key shortcut

I cannot force QKeySequence::toString() to return translated shortcut representation despite the fact that it documentation suggests it should work. The docs say: "The strings, "Ctrl", "Shift", etc. are translated using QObject::tr() in the "QShortcut" context." but I am not completely sure what it means by shortcut context. I am probably doing something wrong...
Here is my example. To make it work, I need to copy qtbase_es.qm from Qt installation directory to my project build directory. When the translation is correctly loaded, the action in the menu correctly shows "Action Control+Intro" which is Spanish translation of the shortcut for "Action Ctrl+Enter". But the tooltip on the main window is still "Action (Ctrl+Enter)". I would expect it to be "Action (Control+Intro)", like in the menu. What am I doing wrong?
#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QMainWindow>
#include <QMenuBar>
#include <QTranslator>
int main(int argc, char *argv[])
{
QTranslator spanish;
qDebug() << spanish.load("qtbase_es.qm"); // should return true if correctly loaded
QApplication a(argc, argv);
QApplication::installTranslator(&spanish);
QMainWindow w;
auto menu = new QMenu("Menu");
auto action = menu->addAction("Action");
action->setShortcutContext(Qt::ApplicationShortcut);
action->setShortcut(Qt::CTRL | Qt::Key_Enter);
w.menuBar()->addMenu(menu);
w.show();
QApplication::processEvents(); // I also tried this line but it is useless...
w.setToolTip(QString("%1 (%2)").arg(action->text(), action->shortcut().toString()));
qDebug() << action->shortcut().toString(); // WRONG: returns Ctrl+Enter but I expect Control+Intro
return a.exec();
}
The QShortcut::toString has a SequenceFormat parameter, defaulted to ProtableText. The documentation of the format states, that portable format is intended for e.g. writing to a file.
The native format is intended for displaying to the user, and only this format performs translations.
Try:
qDebug() << action->shortcut().toString(QKeySequence::NativeText);

Why is QAudioRecorder not recording through the constructor?

header
#ifndef AUDIORECORD_H
#define AUDIORECORD_H
#include <QMediaRecorder>
#include <QAudioRecorder>
#include <QUrl>
class AudioRecorder : public QAudioRecorder
{
Q_OBJECT
public:
AudioRecorder(QObject * parent);
~AudioRecorder(){}
};
#endif // AUDIORECORD_H
source
#include "audiorecord.h"
#include<iostream>
using namespace std;
AudioRecorder::AudioRecorder(QObject * parent = 0)
{
this->setOutputLocation(QUrl::fromLocalFile("test.mp3"));
int x = 0;
while ( x > 10000)
{
this->record();
x++;
}
this->stop();
std::cout<<"\ndsffsdf\n";
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "audiorecord.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QObject p;
AudioRecorder obj(&p);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
This does not produce any error but it does not record also. I am not expecting any quality or full fledged recording.
I just want to see how this recorder works.
That test.mp3 is not getting saved.
What bare minimum can I add or subtract to it to make it record something and save?
Cause
What would be if I tell you 10 000 times: Go buy some milk, while firmly holding your hand, then just before I let you go to say: Ah, forget it? Would you be able to buy the milk?
You are doing the same with your code:
int x = 0;
while ( x > 10000)
{
this->record();
x++;
}
this->stop();
You are calling 10 000 times QAudioRecorder::record, but you do not let Qt get to the event loop and actualy execute your command. Then just before Qt gets to the event loop, you say: stop.
Solution
First of all, you do not need to subclass QAudioRecorder, because you do not add any new functionality to it. Just create an instance of the class and use it.
Second, record and stop are slots. Connect them to the clicked signal of the corresponding push buttons in you GUI, e.g.:
auto *audioRecorder = new QAudioRecorder(this);
...
connect(btnRecord, &QPushButton::clicked, audioRecorder, &QAudioRecorder::record);
connect(btnStop, &QPushButton::clicked, audioRecorder, &QAudioRecorder::stop);
Note: For more information, please take a look at the example from the documentation.

running draw_polygon example in CGAl package in qt widget application

I try to following CGAL example in Qt widget application :
example
main.ccp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.ccp :
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/draw_polyhedron.h>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
void MainWindow::on_pushButton_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this,tr("Open .off model"), "/home", tr("*.off"));
draw_poly(fileName);
}
void MainWindow::draw_poly(QString fileName)
{
QByteArray inBytes;
const char *c;
inBytes = fileName.toUtf8();
c = inBytes.constData();
std::ifstream input(c);
if (!input || !(input >> mesh) || mesh.is_empty()) {
std::cerr << "Not a valid off file." << std::endl;
// return 1;
}
input >> mesh;
CGAL::draw(mesh);
}
when I ran it , it open dialog file to select .off file ,then it shows the following error:
QCoreApplication::exec: The event loop is already running
any help ,please ?
I'm using Qt5 in daily business, and once considered CGAL as possible application base (without going further into this direction – not yet). Hence, this question made me curious.
I digged through the source code of CGAL on github and found out why the error message
QCoreApplication::exec: The event loop is already running
occurs.
For this, I copied the relevant lines from CGAL on github: Polyhedron/include/CGAL/draw_polyhedron.h:
template<class Polyhedron, class ColorFunctor>
void draw(const Polyhedron& apoly,
const char* title,
bool nofill,
const ColorFunctor& fcolor)
{
#if defined(CGAL_TEST_SUITE)
bool cgal_test_suite=true;
#else
bool cgal_test_suite=false;
#endif
if (!cgal_test_suite)
{
int argc=1;
const char* argv[2]={"polyhedron_viewer","\0"};
QApplication app(argc,const_cast<char**>(argv));
SimplePolyhedronViewerQt<Polyhedron, ColorFunctor>
mainwindow(app.activeWindow(), apoly, title, nofill, fcolor);
mainwindow.show();
app.exec();
}
}
Looking at this source code, it becomes obvious that CGAL::draw() is a small ful-featured Qt application in itself which establishs its own QApplication instance. The OP in turn tried to embed the CGAL::draw() in her/his own Qt application. It is not allowed to instance any derivates of QCoreApplication more than once (according to Qt doc. of QApplication):
For any GUI application using Qt, there is precisely one QApplication object, no matter whether the application has 0, 1, 2 or more windows at any given time.
(Emphasizing not mine.)
The CGAL doc. provides an (even shorter) example in Polyhedron/draw_polyhedron.cpp to do this right:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/draw_polyhedron.h>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
int main(int argc, char* argv[])
{
Polyhedron P;
std::ifstream in1((argc>1)?argv[1]:"data/cross.off");
in1 >> P;
CGAL::draw(P);
return EXIT_SUCCESS;
}
but there is no place to insert the QFileDialog at the right point.
Hence, CGAL::draw() is the wrong tool for what OP (probably) intends to do – embed CGAL polyhedron rendering into a Qt application. For this, it is necessary to use the things directly which are called somewhere inside of CGAL::draw().
So, this is what seems appropriate to me:
making SimplePolyhedronViewerQt<Polyhedron, ColorFunctor> a (main or child) widget in OPs Qt application.
I then walked a bit through the github repo to find out from which Qt widget CGAL::SimplePolyhedronViewerQt<Polyhedron, ColorFunctor> is actually derived from and found the following inheritance:
CGAL::SimplePolyhedronViewerQt<Polyhedron, ColorFunctor>
|
V
CGAL::Basic_viewer_qt
|
V
CGAL::QGLViewer
|
+--------------+--------------+
| |
V V
QOpenGLWidget QOpenGLFunctions
So, CGAL::SimplePolyhedronViewerQt<Polyhedron, ColorFunctor> can be used like any QWidget (which involves making it the main window). It can become as well the center widget of a QMainWindow which gets a menu bar/tool bar with the QAction to open the QFileDialog, request a file path, open a file stream with this file path, and load a mesh from this file stream.
There is another minor detail where I stumbled over: The CGAL::Polyhedron has to be given to the CGAL::SimplePolyhedronViewerQt in the constructor and by const reference. To consider this, it's IMHO necessary (after successful loading of mesh) to construct the CGAL::SimplePolyhedronViewerQt instance by new and set/add it to parent widget afterwards. If this is not acceptable it's probably necessary to go even deeper and replace the CGAL::SimplePolyhedronViewerQt by an own implementation, using the source code of the former as “cheat-sheet”.
This is how such an application could look like:
#include <fstream>
#include <QtWidgets>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/draw_polyhedron.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
CGAL::DefaultColorFunctorPolyhedron fColor;
Polyhedron mesh;
// setup UI
QMainWindow qWin;
QToolBar qToolbar;
QAction qCmdLoad(QString::fromUtf8("Load File..."));
qToolbar.addAction(&qCmdLoad);
qWin.addToolBar(&qToolbar);
qWin.show();
// install signal handlers
QObject::connect(&qCmdLoad, &QAction::triggered,
[&qWin, &mesh, &fColor]() {
const QString filePath = QFileDialog::getOpenFileName(
&qWin,
QString::fromUtf8("Open .off model"),
QString::fromUtf8("/home"),
QString::fromUtf8("*.off"));
if (filePath.isEmpty()) return;
std::ifstream fIn(filePath.toUtf8().data());
if (!(fIn >> mesh) || mesh.is_empty()) {
qDebug() << "Loading of" << filePath << "failed!";
return;
}
qWin.setCentralWidget(
new CGAL::SimplePolyhedronViewerQt<Polyhedron, CGAL::DefaultColorFunctorPolyhedron>(
&qWin, mesh, "Basic Polyhedron Viewer", false, fColor));
qWin.centralWidget()->show();
});
// runtime loop
return app.exec();
}
Please, take this with a “grain of salt” – I've no CGAL at hand and couldn't compile/test the above code.
CGAL::draw() already handles the Qt stuff. You are trying to open a mainwindow in another one. Just call CGAL::draw(mesh) in your main() function without anything else and it will work.
EDIT: Which is exactly what Sheff explained in a much more detailed way.

QCompleter::activated disconnected after losing and gaining focus

I found a strange case which I do not understand. Maybe it is a Qt bug, maybe I am doing something wrong.
A header:
// File mylineedit.h
#pragma once
#include <QLineEdit>
#include <QDebug>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = nullptr) : QLineEdit(parent) { }
public slots:
void onCompleterActivated(const QString& text) { qDebug() << "MyLineEdit" << text; }
};
And the main source file:
// File main.cpp
#include <QApplication>
#include <QWidget>
#include <QStringListModel>
#include <QCompleter>
#include <QVBoxLayout>
#include "mylineedit.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QLineEdit* lineEdit1 = new MyLineEdit();
QLineEdit* lineEdit2 = new MyLineEdit();
auto layout = new QVBoxLayout(&w);
layout->addWidget(lineEdit1);
layout->addWidget(lineEdit2);
lineEdit1->setCompleter(new QCompleter());
auto model = new QStringListModel(QStringList() << "A" << "B" << "C");
lineEdit1->completer()->setModel(model);
QObject::connect(lineEdit1->completer(), SIGNAL(activated(QString)), lineEdit1, SLOT(onCompleterActivated(QString)));
w.show();
return a.exec();
}
Once you run this, you can get a completer with values "A", "B", "C" in the first line edit. When you select any of these values, it will print the message to the console. This is correct. But then change focus to the other line edit and then back. Try picking "A", "B", "C" again. No message is printed out, the signal/slot seems disconnected. Any ideas?
Tested with MinGW 5.3.0 and MSVC 2015 using with Qt 5.9.2.
I modified your sample slightly and tried to reproduce the behavior you described but I couldn't:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version: " << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
QWidget qWin;
QVBoxLayout qVBox;
QLineEdit qEdit1;
qVBox.addWidget(&qEdit1);
QCompleter qCompl1;
QStringListModel qComplModel(QStringList() << "A" << "B" << "C");
qCompl1.setModel(&qComplModel);
qEdit1.setCompleter(&qCompl1);
QLineEdit qEdit2;
qVBox.addWidget(&qEdit2);
qWin.setLayout(&qVBox);
qWin.show();
// install signal handlers
QObject::connect(&qCompl1,
static_cast<void(QCompleter::*)(const QString&)>(
&QCompleter::activated),
[](const QString &text)
{
qDebug() << "Activated: " << text;
});
// run-time loop
return app.exec();
}
The significant differences in my sample:
I used Qt5 style signal handlers (as I'm used to).
I didn't new the Qt widgets (as I'm used to when I write minimal samples).
For me, it's hard to believe that one of these changes makes your described issue unbroken.
I compiled and tested with VS2013, Qt 5.9.2 on Windows 10 (64 bit):
I did the following interactions:
click in qEdit1
type A and click on item A in the popup menu
Output:
Activated: "A"
I continued with:
click in qEdit2
type B
click in qEdit1
erase text, type B, and click on item B in the popup menu
Output:
Activated: "B"
It works like expected.
After some conversation, I had a look at woboq.org in the source code of QLineEdit:
The interesting part is in QLineEdit::focusOutEvent:
if (d->control->completer()) {
QObject::disconnect(d->control->completer(), 0, this, 0);
}
If I read this right, all signal handlers of QLineEdit (emitted by the set completer) are disconnected. I believe this is the reason for the observed issue. (Therefore, it works for lambdas and methods of other classes.)

How to display right-to-left written ancient characters in Qt

I have a project which must support multiple ancient languages. My problem is that I have an ancient Old Turkic character (the language is written right-to-left) but I can't display the characters in a Qt Label like this:
//main.cpp
#include <QApplication>
#include <QString>
#include <QLabel>
int main(int argc, char** argv[])
{
QApplication app(argc, argv);
QString str = "\U00010C00"; // Character I wanted to display
QLabel *label = new QLabel(str);
label -> show();
return app.exec();
}
When I run this, in the label it prints a square which indicates that, I think, the character couldn't be found. How can I fix this problem?
A square is being displayed at the right of the window, so there is not a problem with the location of the character. My OS is Ubuntu 12.04 x64 and my Qt version is 5, by the way. I have the Old Turkic Unicode font.
You need to tell the label which font it should use.
QFont labelFont = QFont( "Old Turkic" );
label->setfont( labelFont );