user interface inside QSystemTrayIcon context menu - c++

I'm creatig tray icon application and i want create advanced context menu, like on pictures below, but i only know, how to create simple menues with
QMenu* menu = new QMenu()
menu->addAction(QIcon(), "item", item1Click);
trayIcon->setContextMenu(menu);
How can i do this?

Well, is supose, it's better to show you code:
main.h
#ifndef MAIN_H
#define MAIN_H
#include <QtWidgets/QApplication>
#include <QtCore/QDebug>
#include <QtGui/QIcon>
#include <QtWidgets/QSystemTrayIcon>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenu>
#include <QtWidgets/QWidgetAction>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QLabel>
class SpinBoxAction : public QWidgetAction
{
public:
SpinBoxAction (const QString& title) : QWidgetAction (NULL)
{
QWidget* Widget = new QWidget (NULL);
QHBoxLayout* Layout = new QHBoxLayout();
QLabel* Label = new QLabel (title);
Layout->addWidget (Label);
SpinBox = new QSpinBox(NULL);
Layout->addWidget (SpinBox);
Widget->setLayout (Layout);
setDefaultWidget(Widget);
}
QSpinBox* spinBox()
{
return SpinBox;
}
private:
QSpinBox* SpinBox;
};
class Reciever : public QObject
{
private:
QSystemTrayIcon* trayIcon;
public:
Reciever()
{
}
void setup(QSystemTrayIcon* trayIcon)
{
this->trayIcon = trayIcon;
}
Q_OBJECT
public slots:
void action(int i)
{
trayIcon->showMessage("changed", "spin box value has been changed", QSystemTrayIcon::NoIcon, 1000);
}
void onActivated(QSystemTrayIcon::ActivationReason reason)
{
trayIcon->showMessage("activated", "tray icon has been activated", QSystemTrayIcon::NoIcon, 1000);
}
};
#endif // MAIN_H
main.cpp
#include <main.h>
#include <QtWidgets/QApplication>
#include <QtCore/QDebug>
#include <QtGui/QIcon>
#include <QtWidgets/QSystemTrayIcon>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenu>
#include <QtWidgets/QWidgetAction>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QHBoxLayout>
int main(int argc, char** argv)
{
Reciever* reciever = new Reciever();
QApplication app(argc, argv);
QSystemTrayIcon* trayIcon = new QSystemTrayIcon(QIcon(":/images/abc.png"));
if (!trayIcon->isSystemTrayAvailable()) exit(1);
QMenu* menu = new QMenu();
SpinBoxAction* spinBoxAction = new SpinBoxAction("Action Title");
menu->addAction(spinBoxAction);
QObject::connect(spinBoxAction->spinBox(), SIGNAL(valueChanged(int)), reciever, SLOT(action(int)));
trayIcon->setContextMenu(menu);
trayIcon->setVisible(true);
QObject::connect(trayIcon, &QSystemTrayIcon::activated, reciever, &Reciever::onActivated);
reciever->setup(trayIcon);
return app.exec();
}
And it leads to simple list menu with one empty element:

Related

How to display a QChartView inside a QStackedWidget?

I want my form to have a QStackedWidget with 2 (at least) pages and each of them has a QChartView.
In the form editor, through the 'promote' menu, I made a QChartView from QGraphicView. (screenshoot (so far there is only 1 QChartView on it - so that i can see which page is open)).
From the main window, when one of the buttons is pressed, I want to open the above windows in a loop:
void Widget::ShowStudioCharts() noexcept
{
for(auto & e : this->userInfoVector){
Form *pForm = new Form();
pForm->provideStudioData(&e.studiosStats, e.nickname);
pForm->processStudioStats();
pForm->show();
}
}
I tried to do it like this:
Form.h
#ifndef FORM_H
#define FORM_H
#include <QWidget>
#include <QPieSeries>
#include <QChart>
#include <QChartView>
#include <QGridLayout>
#include <vector>
#include <map>
#include <QStackedWidget>
#include <QtGlobal>
#include <QRectF>
#include <QRect>
#include <QPushButton>
namespace Ui {
class Form;
}
class Form : public QWidget
{
Q_OBJECT
public:
explicit Form(QWidget *parent = nullptr);
~Form();
void provideStudioData(std::map<std::string, std::size_t> *studiosStats, const std::string &nickname) noexcept;
void processStudioStats() noexcept;
private slots:
void on_pushButton_2_clicked();
private:
std::vector<std::map<std::string, size_t>*> stats;
std::vector<std::string> nicknames;
Ui::Form *ui;
};
#endif // FORM_H
Form.cpp
#include "form.h"
#include "ui_form.h"
#include <QPieSeries>
#include <QPieSlice>
#include <QChart>
using namespace QtCharts;
Form::Form(QWidget *parent) :
QWidget(parent),
ui(new Ui::Form)
{
ui->setupUi(this);
}
Form::~Form()
{
delete ui;
}
void Form::provideStudioData(std::map<std::string, size_t> *studiosStats, const std::string &nickname) noexcept
{
this->stats.push_back(studiosStats);
this->nicknames.push_back(nickname);
}
void Form::processStudioStats() noexcept
{
srand(time(0));
QPieSeries *series = new QPieSeries();
// for (const auto & e : this->stats ){
// //QBarSet *set0 = new QBarSet("1");
// for ( const auto & a : *e){
// //*set0 << a.second;
// qDebug( (a.first + " " + std::to_string(a.second)).c_str());
// }
// }
for ( const auto & a : *this->stats[0]){
QPieSlice * slice = new QPieSlice();
slice->setColor(QColor(rand()%255, rand()%255, rand()%255));
slice->setValue(a.second);
slice->setLabel(a.first.c_str());
series->append(slice);
}
QChart *chart = new QChart();
chart->setAnimationOptions(QChart::AnimationOption::AllAnimations);
chart->addSeries(series);
//chart->setPlotArea(QRectF(200,0,1400,1100));
//chart->legend()->detachFromChart();
chart->legend()->setBackgroundVisible(true);
chart->legend()->setBrush(QBrush(QColor(128, 128, 128, 128)));
chart->legend()->setPen(QPen(QColor(192, 192, 192, 192)));
//chart->legend()->setGeometry(QRectF(20,20,200,1000));
chart->setTitle(QString::fromStdString(this->nicknames[0]));
this->setWindowTitle(QString::fromStdString(this->nicknames[0]));
chart->legend()->setAlignment(Qt::AlignLeft);
ui->graphicsView = new QChartView(chart);
ui->graphicsView->show();
//ui->stackedWidget->show();
}
void Form::on_pushButton_2_clicked()
{
if(0 == this->ui->stackedWidget->currentIndex())
this->ui->stackedWidget->setCurrentIndex(1);
else if(1 == this->ui->stackedWidget->currentIndex())
this->ui->stackedWidget->setCurrentIndex(0);
}
The code is compiled, windows are opened. But the problem is that my chart is displayed in another window above the opened one.
This is obviously the result of
ui->graphicsView->show();
But if i remove this line, then the graph is not visible at all.
Help please, thanks in advance.
Doing ui->graphicsView = new QChartView(chart); does not replace the QChartView, you are just assigning the pointer. The solution is to reuse the existing QChartView so it changes to: ui->graphicsView->setChart(chart);.

how to use scene object of main file in other file?

I tried to make tictactoe game using Qt and Qgraphicsview but when I draw x on board using Graphicstextitem in mousePressEvent , X does not appear. how fix that ?
I think the problem is that scene of textitem Different from scene of main file but I do not know how fix that.
main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game *gm = new Game;
Game *rect1=new Game;
gm->scenc->setSceneRect(0,0,800,600);
rect1->setRect(160,100,150,150);
gm->scenc->addItem(rect1);
gm->view->setScene(gm->scenc);
gm->view->show();
return a.exec();
}
in game.cpp:
#include <game.h>
Game::Game()
{
scenc= new QGraphicsScene;
view = new QGraphicsView;
text= new QGraphicsTextItem;
}
void Game::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->buttons() == Qt::LeftButton )
{
text->setPlainText("X");
text->setFont(QFont("Tahoma",24));
text->setPos((160+160+120)/2,140);
scenc->addItem(text);
}
}
in game.h :
class Game : public QObject , public QGraphicsRectItem
{
Q_OBJECT
public:
Game();
QGraphicsScene *scenc;
QGraphicsView *view;
QGraphicsTextItem *text;
void mousePressEvent(QGraphicsSceneMouseEvent *event);
};
The following example illustrates how to do it the right way. Firstly, you have to notice, that Game::mousePressEvent doesn't override any virtual function. It's a good habit to use the override keyword and to drop the virtual keyword in order to be sure, that a virtual function is overwritten.
Game is not derived from QGraphicsScene and has therefore no mousePressEvent member.
Try the following example app.
MyScene.h
#pragma once
#include <QWidget>
#include <QDebug>
#include <QHBoxLayout>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsTextItem>
#include <QGraphicsSceneMouseEvent>
class MyScene : public QGraphicsScene {
Q_OBJECT
public:
MyScene(QWidget* parent = nullptr) : QGraphicsScene(parent) {
setSceneRect(0, 0, 800, 600);
}
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* mouseEvent) override {
if (mouseEvent->buttons() == Qt::LeftButton)
{
auto text = new QGraphicsTextItem;
addItem(text);
text->setPlainText("X");
text->setPos(mouseEvent->scenePos());
}
}
private:
QGraphicsView* mView;
QGraphicsTextItem* mText;
};
main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsTextItem>
#include "MyScene.h"
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
auto scene = new MyScene;
auto view = new QGraphicsView;
view->setScene(scene);
view->show();
return a.exec();
}

Can someone explain how this code works? I'm using Qt Creator C++

I have a question with some of the code for a tutorial I'm following for Qt Creator. My first question is how is MyRect() (in file "main.cpp" on line MyRect * rect = new MyRect();) was created? I thought it was only a class and not a function. Could someone explain that?
I'm also having trouble understanding how (under "myrect.cpp") the keyPressEvent function is called whenever I press an arrow key. How does the function know to respond without me calling it? If it has been called and I've just missed it, could someone specify where, thanks.
main.cpp:
#include <QApplication>
#include <QGraphicsScene>
#include "myrect.h"
#include <QGraphicsView>
using namespace std;
int main(int argc, char *argv[]){
QApplication a(argc, argv);
// create a scene
QGraphicsScene * scene = new QGraphicsScene();
// create an item to put into the scene
MyRect * rect = new MyRect();
rect->setRect(0,0,100,100);
// add the item to the scene
scene->addItem(rect);
//Make item focusable
rect->setFlag(QGraphicsItem::ItemIsFocusable);
rect->setFocus();
// add a view to visualize the scene
QGraphicsView * view = new QGraphicsView(scene);
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->show();
return a.exec();
}
myrect.cpp:
#include "MyRect.h"
#include <QGraphicsScene>
#include <QKeyEvent>
#include "bullet.h"
#include <QDebug>
void MyRect::keyPressEvent(QKeyEvent *event){
if(event->key() == Qt::Key_Left){
setPos(x()-10,y());
}
else if(event->key() == Qt::Key_Right){
setPos(x()+10,y());
}
else if(event->key() == Qt::Key_Up){
setPos(x(),y()-10);
}
else if(event->key() == Qt::Key_Down){
setPos(x(),y()+10);
}
else if(event->key() == Qt::Key_Space){
//creates a bullet
Bullet* bullet = new Bullet();
bullet->setPos(x(),y());
scene()->addItem(bullet);
}
}
myrect.h:
#ifndef MYRECT_H
#define MYRECT_H
#include <QGraphicsRectItem>
class MyRect: public QGraphicsRectItem{
public:
void keyPressEvent(QKeyEvent* event);
};
#endif // MYRECT_H
bullet.cpp:
#include "Bullet.h"
#include <QTimer>
Bullet::Bullet(){
//draw rect
setRect(0,0,10,50);
//connect
QTimer * timer = new QTimer();
connect(timer,SIGNAL(timeout()),this,SLOT(move()));
timer->start(50);
}
void Bullet::move(){
//move bullet up
setPos(x(),y()-10);
}
bullet.h:
#ifndef BULLET_H
#define BULLET_H
#include <QGraphicsRectItem>
#include <QObject>
class Bullet: public QObject, public QGraphicsRectItem{
Q_OBJECT
public:
Bullet();
public slots:
void move();
};
#endif // BULLET_H

Scrolling list of labels on Qt

I'm trying to create a scrollbar for my labels. For the moment, if the users create too many labels, the sizes of the button and of the text zone are reduced, that's why I wanted to create a scrollbar then if there is too many labels, they will not change the aspect of the window.
This is my actual code :
#include <iostream>
#include <QApplication>
#include <QPushButton>
#include <QLineEdit>
#include <QWidget>
#include <QFormLayout>
#include "LibQt.hpp"
LibQt::LibQt() : QWidget()
{
this->size_x = 500;
this->size_y = 500;
QWidget::setWindowTitle("The Plazza");
setFixedSize(this->size_x, this->size_y);
manageOrder();
}
LibQt::~LibQt()
{
}
void LibQt::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Escape)
QCoreApplication::quit();
else
QWidget::keyPressEvent(event);
}
void LibQt::manageOrder()
{
this->converLayout = new QFormLayout;
this->testline = new QLineEdit;
this->m_button = new QPushButton("Send");
this->m_button->setCursor(Qt::PointingHandCursor);
this->m_button->setFont(QFont("Comic Sans MS", 14));
this->converLayout->addRow("Order : ", this->testline);
this->converLayout->addWidget(this->m_button);
QObject::connect(m_button, SIGNAL(clicked()), this, SLOT(ClearAndGetTxt()));
CreateLabel("test");
CreateLabel("test2");
}
void LibQt::CreateLabel(std::string text)
{
QString qstr = QString::fromStdString(text);
this->label = new QLabel(qstr);
this->converLayout->addWidget(this->label);
this->setLayout(converLayout);
}
std::string LibQt::ClearAndGetTxt()
{
QString txt = this->testline->text();
if (!txt.isEmpty())
{
this->usertxt = txt.toStdString();
std::cout << this->usertxt << std::endl;
this->testline->clear();
CreateLabel(this->usertxt);
return (this->usertxt);
}
return (this->usertxt);
}
std::string LibQt::getUsertxt()
{
return (this->usertxt);
}
And this is the .hpp :
#ifndef _LIBQT_HPP_
#define _LIBQT_HPP_
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include <QKeyEvent>
class LibQt : public QWidget
{
Q_OBJECT
public:
LibQt();
~LibQt();
void manageOrder();
std::string getUsertxt();
void keyPressEvent(QKeyEvent *event);
void keyPressEventEnter(QKeyEvent *event);
void CreateLabel(std::string text);
public slots:
std::string ClearAndGetTxt();
protected:
int size_x;
int size_y;
QPushButton *m_button;
QLineEdit *testline;
std::string usertxt;
QLabel *label;
QFormLayout *converLayout;
};
#endif /* _LIBQT_HPP_ */
there are different solutions depending on what precisely do you want
QTextEdit is Qt widget class for scrollable text. By turning off text interaction flags, frame style and unsetting background color you will basically get scrollable QLabel
QScrollArea as a more generic solution

Managing the escape key to quit a program

I don't know how to implement the managing of the escape key to quit the program. I don't know either where to put it in my code, because if I put it in a method, how can it quit anywhere?
This is my actual code :
#include <iostream>
#include <QApplication>
#include <QPushButton>
#include <QLineEdit>
#include <QFormLayout>
#include <QDebug>
#include "LibQt.hpp"
LibQt::LibQt() : QWidget()
{
this->size_x = 500;
this->size_y = 500;
QWidget::setWindowTitle("The Plazza");
setFixedSize(this->size_x, this->size_y);
manageOrder();
}
LibQt::~LibQt()
{
}
void LibQt::manageOrder()
{
this->testline = new QLineEdit;
this->m_button = new QPushButton("Send Order");
QFormLayout *converLayout = new QFormLayout;
this->m_button->setCursor(Qt::PointingHandCursor);
this->m_button->setFont(QFont("Comic Sans MS", 14));
converLayout->addRow("Order : ", this->testline);
converLayout->addWidget(this->m_button);
this->setLayout(converLayout);
QObject::connect(m_button, SIGNAL(clicked()), this, SLOT(ClearAndGetTxt()));
}
std::string LibQt::ClearAndGetTxt()
{
QString txt = this->testline->text();
this->usertxt = txt.toStdString();
std::cout << this->usertxt << std::endl;
this->testline->clear();
return (this->usertxt);
}
std::string LibQt::getUsertxt()
{
return (this->usertxt);
}
and this is my .hpp
#ifndef _LIBQT_HPP_
#define _LIBQT_HPP_
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QKeyEvent>
#include <QCheckBox>
#include <QPlainTextEdit>
class LibQt : public QWidget
{
Q_OBJECT
public:
LibQt();
~LibQt();
void manageOrder();
std::string getUsertxt();
public slots:
std::string ClearAndGetTxt();
protected:
int size_x;
int size_y;
QPushButton *m_button;
QLineEdit *testline;
std::string usertxt;
};
#endif /* _LIBQT_HPP_ */
You need to override the method void QWidget::keyPressEvent(QKeyEvent *event). It will look like this for you :
void LibQt::keyPressEvent(QKeyEvent* event)
{
if(event->key() == Qt::Key_Escape)
{
QCoreApplication::quit();
}
else
QWidget::keyPressEvent(event)
}
I know you solved this issue, and my solution is in Python, but other people may find this useful. Essentially, you can implement this feature as an action:
w = LibQt() # QWidget().
escape = QAction('Escape', w)
escape.setShortcut(QKeySequence('Esc'))
escape.setShortcutContext(Qt.WidgetWithChildrenShortcut) # acts as an event filter.
escape.triggered.connect(w.close)
w.addAction(escape)
Obviously, with first line removed, this code may be added to class constructor.