Virtual keyboard or onscreen keyboard for QtWidgets applications? - qt

I'm going to deploy the qtvirtualkeyboard in my widget-based application like so:
#include <QtWidgets>
int main(int argc, char *argv[]) {
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
QApplication app(argc, argv);
QMainWindow window;
QLineEdit input(&window);
input.move(250, 250);
window.show();
return app.exec();
}
But the only issue is that the virtual keyboard input panel hides the underlying widgets and cover them!
How should I achieve this?
Is there any document or solution for widgets-based applications?

you just need to add this line in main.cpp
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
and will work Virtual Keyboard in Qtwidgets))

Finally got the solution!
You just need to call QGuiApplication::inputMethod() to get the application-wide Qt input method and then call QInputMethod::keyboardRectangle() and QInputMethod::isVisible() to get input method properties then remain a calculation based on your widget position and keyboard coordinate, here is a full-working sample to share:
lineedit.h:
class LineEdit :public QLineEdit {
Q_OBJECT
public:
LineEdit(QWidget *parent = nullptr);
LineEdit(const QString&, QWidget *parent = nullptr);
protected:
bool event(QEvent*) override;
private:
bool _moved = false;
int _lastDiff = 0;
};
lineedit.cpp:
LineEdit::LineEdit(QWidget *parent) :QLineEdit(parent) {
setAttribute(Qt::WA_InputMethodEnabled, true);
setInputMethodHints(inputMethodHints() | Qt::InputMethodHint::ImhDigitsOnly);
}
LineEdit::LineEdit(const QString& txt, QWidget *parent) : QLineEdit(txt, parent) {
setAttribute(Qt::WA_InputMethodEnabled, true);
setInputMethodHints(inputMethodHints() | Qt::InputMethodHint::ImhDigitsOnly);
}
bool LineEdit::event(QEvent* e) {
const auto keyboard_rect = QGuiApplication::inputMethod()->keyboardRectangle();
const auto keyboard_visible = QGuiApplication::inputMethod()->isVisible();
const auto global_y = QWidget::mapToGlobal(rect().topLeft()).y() + height();
const auto k_global_y = keyboard_rect.topLeft().y();
const auto diff = k_global_y - global_y;
const auto need_to_move = diff < 0;
/* move main widget */
if (keyboard_visible && !_moved && need_to_move) {
_moved = true;
_lastDiff = diff;
const auto g = parentWidget()->frameGeometry();
parentWidget()->move(g.x(), g.y() - qAbs(_lastDiff));
}
/* roll back */
if (!keyboard_visible && _moved) {
_moved = false;
const auto g = parentWidget()->frameGeometry();
parentWidget()->move(g.x(), g.y() + qAbs(_lastDiff));
}
return QLineEdit::event(e);
}
main.cpp:
#include <QtWidgets>
#define W 1024
#define H 768
int main(int argc, char *argv[]) {
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
QApplication app(argc, argv);
QMainWindow window(nullptr, Qt::FramelessWindowHint);
LineEdit lineedit1(&window);
lineedit1.move(100, 450);
LineEdit lineedit2(&window);
lineedit2.move(100, 100);
window.resize(W, H);
window.show();
return app.exec();
}
results:

Related

How to set icon at left of text in a QLIstWidgetItem?

I have a QListWidget which is used in iconMode as the viewMode. When I set an QIcon and the text for a QListWidgetItem, icon is showed on top of the text. If I use the QlistWidget in listMode as the viewMode, icon is shown at the left side of the text. How to show the icon at the left side of the text when the QListWidget is in iconMode ?
I tried setTextAlignment(Qt::AlignRight) for QLIstWidgetItems. But it didn't work.
The decorationPosition property of QStyleOptionViewItem determines the position of the icon, so the solution is to modify those properties:
Override viewOptions() method of QListWidget:
#include <QtWidgets>
class ListWidget: public QListWidget
{
public:
using QListWidget::QListWidget;
protected:
QStyleOptionViewItem viewOptions() const override{
QStyleOptionViewItem option = QListWidget::viewOptions();
option.decorationPosition = QStyleOptionViewItem::Left;
return option;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ListWidget w;
w.setViewMode(QListView::IconMode);
for (QStyle::StandardPixmap sp: {
QStyle::SP_ArrowBack,
QStyle::SP_ArrowDown,
QStyle::SP_ArrowForward,
QStyle::SP_ArrowLeft,
QStyle::SP_ArrowRight,
QStyle::SP_ArrowUp})
{
QIcon icon = QApplication::style()->standardPixmap(sp);
QListWidgetItem *it = new QListWidgetItem("foo");
it->setIcon(icon);
w.addItem(it);
}
w.show();
return a.exec();
}
Override initStyleOption() method of QStyledItemDelegate
#include <QtWidgets>
class StyledItemDelegate: public QStyledItemDelegate
{
public:
using QStyledItemDelegate::QStyledItemDelegate;
protected:
void initStyleOption(QStyleOptionViewItem *option,
const QModelIndex &index) const override
{
QStyledItemDelegate::initStyleOption(option, index);
option->decorationPosition = QStyleOptionViewItem::Left;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QListWidget w;
w.setViewMode(QListView::IconMode);
StyledItemDelegate *delegate = new StyledItemDelegate(&w);
w.setItemDelegate(delegate);
for (QStyle::StandardPixmap sp: {
QStyle::SP_ArrowBack,
QStyle::SP_ArrowDown,
QStyle::SP_ArrowForward,
QStyle::SP_ArrowLeft,
QStyle::SP_ArrowRight,
QStyle::SP_ArrowUp})
{
QIcon icon = QApplication::style()->standardPixmap(sp);
QListWidgetItem *it = new QListWidgetItem("foo");
it->setIcon(icon);
w.addItem(it);
}
w.show();
return a.exec();
}

Qt: How to link hand coded UI with UI builder?

I am looking for an easy way to link hand coded design to the UI for widgets applications in Qt. I plan to use the UI builder to easily adjust the layouts and obtain proper spacing, which I find hard to do without the UI builder.
I want to create a 3x3 grid of buttons for which I plan to use QVector< QVector<QPushButton*> > (I am not sure how I would do this in UI builder.)
Here is what I have tried, Why are the buttons not displayed even when I set the parent of each button to the widget ?
main.cpp
#include "window.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QPushButton>
namespace Ui {
class Window;
}
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
~Window();
private:
Ui::Window *ui;
static const int tiles = 50, height = 600, width = 500;
QVector< QVector<QPushButton*> > cells;
};
#endif // WINDOW_H
window.cpp
#include "window.h"
#include "ui_window.h"
Window::Window(QWidget *parent) :
QWidget(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
this->resize(width, height);
int j = 0;
for(auto &row : cells)
{
int i = 0;
for(auto &col : row)
{
col = new QPushButton(this);
col->setGeometry(i, j, tiles, tiles);
i += tiles;
}
j += tiles;
}
}
Window::~Window()
{
delete ui;
for(auto &row : cells)
{
for(auto &col : row)
{
delete col;
}
}
}
Any help would be appreciated.
The vectors are empty, so you iterate over nothing. Instead of managing these manually, you could leverage the grid layout.
Alas, you're complicating things unnecessarily with all the manual memory management and geometry management. It's unnecessary. All you need to do is to add widgets to the layout you allude to. And even then, I don't see how relegating the layout to a .ui file helps you since there the layout must be empty. So yes: you can set spacings, but you won't see them until you run the code. So it seems like a pointless exercise, unless you have other elements you're not telling us about (why aren't you - you went so far already).
Below is a minimum example that simplifies it as much as practicable, but see this answer and the links therein for more idea.
// https://github.com/KubaO/stackoverflown/tree/master/questions/button-grid-43214317
#include <QtWidgets>
namespace Ui { class Window {
public:
// Approximate uic output
QGridLayout *layout;
void setupUi(QWidget * widget) {
layout = new QGridLayout(widget);
}
}; }
class Window : public QWidget
{
Q_OBJECT
Ui::Window ui;
QPushButton * buttonAt(int row, int column) {
auto item = ui.layout->itemAtPosition(row, column);
return item ? qobject_cast<QPushButton*>(item->widget()) : nullptr;
}
public:
explicit Window(QWidget *parent = {});
};
Window::Window(QWidget *parent) : QWidget(parent) {
ui.setupUi(this);
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 6; ++j)
{
auto b = new QPushButton(QStringLiteral("%1,%2").arg(i).arg(j));
ui.layout->addWidget(b, i, j);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
#include "main.moc"

how to clickable a QGraphicsTextItem?

I have a QDialog for beginning of my game.in this class I have a QGraphicsTextItem. I want to it is clickable. When user clicked play game start. I do this but not work.
class Mydialog_start:public QDialog
{
Q_OBJECT
public:
explicit Mydialog_start(QWidget *parent = 0);
signals:
public slots:
void on_play_clicked();
void on_exit_clicked();
private:
QGraphicsScene* scene;
QGraphicsView* view;
QPixmap image;
QBrush brush;
QGraphicsTextItem* text;
QFont font;
const int x_size;
const int y_size;
};
Mydialog_start::Mydialog_start(QWidget *parent) :
QDialog(parent),x_size(400),y_size(400)
{
scene=new QGraphicsScene(this);
view=new QGraphicsView(this);
view->setScene(scene);
scene->setSceneRect(0,0,x_size,y_size);
image.load(":picture/image/background.jpg");
image=image.scaled(x_size,y_size);
brush.setTexture(image);
scene->setBackgroundBrush(brush);
font.setBold(true);
font.setPointSize(40);
font.setItalic(true);
text=scene->addText("play",font);
text->setDefaultTextColor(QColor("red"));
text->setPos(100,300);
this->setFixedSize(400,400);
connect(text,SIGNAL(linkActivated(QString("play"))),this,SLOT(on_play_clicked()));
}
void Mydialog_start::on_play_clicked()
{
accept();
}
void Mydialog_start::on_exit_clicked()
{
reject();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
Mydialog_start dialog;
dialog.exec();
if( dialog.exec()==QDialog::Accepted)
{
w.show();
}
else
{
w.close();
}
}
Not quite sure whether you needed your text item to be "editable" - see Mitch's comment...
It seems that you need your item to be "clickable" - then all you need are some flags:
text->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);

Qt Widget temporarily fullscreen

Consider a QWidget, normally a child in some Layout.
Supposed I want to make it fullScreen for a while, then have it return to it's old spot.
QWidget::setFullScreen() requires that the widget needs to be an independent window - any ideas how to work it out?
The simplest way I can see is to reparent to 0. Something like this:
#include <QApplication>
#include <QPushButton>
class MyButton : public QPushButton
{
public:
MyButton(QWidget* parent) : QPushButton(parent) {}
void mousePressEvent(QMouseEvent*) {
this->setParent(0);
this->showMaximized();
this->show();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget mainWidget;
MyButton button(&mainWidget);
mainWidget.show();
return a.exec();
}
I have modified the previous example. The previous example never goes back to normal screen.
Just copy paste the code and it will run.
#include <QApplication>
#include <QPushButton>
class MyButton : public QPushButton
{
public:
MyButton(QWidget* parent) : QPushButton(parent) {
m_pParent = parent;
maxMode = false;
}
QWidget * m_pParent;
bool maxMode;
Qt::WindowFlags m_enOrigWindowFlags;
QSize m_pSize;
void mousePressEvent(QMouseEvent*) {
if (maxMode== false)
{
m_enOrigWindowFlags = this->windowFlags();
m_pSize = this->size();
this->setParent(0);
this->setWindowFlags( Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
this->showMaximized();
maxMode = true;
}
else
{
this->setParent(m_pParent);
this ->resize(m_pSize);
this->overrideWindowFlags(m_enOrigWindowFlags);
this->show();
maxMode = false;
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget mainWidget;
MyButton button(&mainWidget);
mainWidget.show();
return a.exec();
}

Qt: How to draw a dummy line edit control

I have a QPainter, and a rectangle.
i'd like to draw a QLineEdit control, empty. Just to draw it, not to have a live control. How do I do that? I have tried QStyle::drawPrimitive to no avail. nothing gets drawn.
QStyleOption option1;
option1.init(contactsView); // contactView is the parent QListView
option1.rect = option.rect; // option.rect is the rectangle to be drawn on.
contactsView->style()->drawPrimitive(QStyle::PE_FrameLineEdit, &option1, painter, contactsView);
Naturally, i'd like the drawn dummy to look native in Windows and OSX.
Your code is pretty close, but you would have to initialize the style from a fake QLineEdit. The following is based on QLineEdit::paintEvent and QLineEdit::initStyleOption.
#include <QtGui>
class FakeLineEditWidget : public QWidget {
public:
explicit FakeLineEditWidget(QWidget *parent = NULL) : QWidget(parent) {}
protected:
void paintEvent(QPaintEvent *) {
QPainter painter(this);
QLineEdit dummy;
QStyleOptionFrameV2 panel;
panel.initFrom(&dummy);
panel.rect = QRect(10, 10, 100, 30); // QFontMetric could provide height.
panel.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth,
&panel,
&dummy);
panel.midLineWidth = 0;
panel.state |= QStyle::State_Sunken;
panel.features = QStyleOptionFrameV2::None;
style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &painter, this);
}
};
int main(int argc, char **argv) {
QApplication app(argc, argv);
FakeLineEditWidget w;
w.setFixedSize(300, 100);
w.show();
return app.exec();
}

Resources