QPainter's drawGlyphRun not rendering anything on QPixmap - qt

in order to create a LaTeX rendering engine from scratch (including both simple text and math formulas, with AMS math glyphs stored in TrueType font files), following Qt classes has been chosen to draw a glyph on given position: QRawFont, QGlyphRun, QPainter, QPixmap.
However, snippet below based on them does NOT render anything. In principle, it should
load glyphs from a True Type font file using QRawFont class
render a glyph on a QPixmap using QPainter and its drawGlyphRun() function
Here goes the snippet:
#include <QGuiApplication>
#include <QPixmap>
#include <QPainter>
#include <QGlyphRun>
#include <QRawFont>
int main(int argc, char* argv[]){
QGuiApplication app(argc, argv);
QRawFont math_raw_font(QString("cmmi10.ttf"), 10, QFont::PreferDefaultHinting);
QVector<quint32>* my_glyphs = new QVector<quint32>;
my_glyphs->push_back(10);
QGlyphRun math_glyph_run;
math_glyph_run.setRawFont(math_raw_font);
math_glyph_run.setGlyphIndexes(*my_glyphs);
math_glyph_run.setBoundingRect(QRectF(0,0,200,200));
QPixmap img(200, 200);
img.fill(Qt::white);
QPainter my_painter(&img);
my_painter.setPen(Qt::red);
my_painter.drawGlyphRun(QPointF(100,100), math_glyph_run);
auto ok = img.save("output.png");
return 0;
}
So far, I have
verified validity of the TTF file using QRawFont's isValid() function and Ubuntu's font manager using command font-manager cmmi10.ttf
verified glyphs using QGlyphRuns's glyphIndexes()
verified valid rendering system using QPainter's drawText() function, which works OK
I have already read Qt documentation. I will be gratefull for any tip or advice.

Related

Increase QTabWidget tab size while using custom palette

My app uses a QTabWidget. I want the tabs to fill the entire length of the tab bar.
My app also uses a palette to set the colors of all widgets, forms, etc.
I found that I can set the tab size as intended like so:
ui->tabWidget->setStyleSheet(QString("QTabBar::tab { width: %1px; }").arg(ui->tabWidget->size().width()/ui->tabWidget->count()));
But this causes the tab widget and all of its children to ignore my palette.
How can I use my palette and also increase the tab size?
I tried to reproduce your described behavior, but I was not able to do so. I'm using Qt 5.13.0, maybe it is in older version. At first I also thought, that I reproduced your behavior, but then I recognized, that I just didn't fully understood the options in QPalette, which really has a lot of ColorGroups and ColorRoles with different meanings.
Try the following simple test runner in order to verify it with your Qt Version.
#include <QApplication>
#include <QTabWidget>
#include <QFrame>
#include <QHBoxLayout>
#include <QPushButton>
int main(int argc, char** args) {
QApplication app(argc, args);
auto p=app.palette();
p.setColor(QPalette::ColorGroup::Active, QPalette::ColorRole::Background, QColor("red"));
p.setColor(QPalette::ColorGroup::Active, QPalette::ColorRole::Foreground, QColor("blue"));
p.setColor(QPalette::ColorGroup::Active, QPalette::ColorRole::ButtonText, QColor("magenta"));
app.setPalette(p);
auto w= new QTabWidget;
auto f=new QFrame;
f->setLayout(new QHBoxLayout);
f->layout()->addWidget(new QPushButton("Test"));
w->addTab(f,"Tab1");
w->setStyleSheet(QString("QTabBar::tab { width: %1px; height: %1px }").arg(100));
w->show();
app.exec();
}

Restore geometry and state of an arbitrary QDialog

In our applications we are using customizable dialogs using exhaustively QSplitter, so that our customers can rearrange the dialogs to fit their needs.
(Sometimes we are also using QDockWidget, but this seems to be similar.)
Now, it is very annoying to rearrange the dialog every time it is opened again. Or even between different starts of the program.
After consulting the documentation I was able to restore the state and the geometry of a specific dialog containing one QSplitter.
#include <QApplication>
#include <QLabel>
#include <QDebug>
#include <QSplitter>
#include <QPushButton>
#include <QTextEdit>
#include <QDialog>
#include <QSettings>
#include <QHBoxLayout>
int main(int argc, char** args) {
QApplication app(argc, args);
app.setOrganizationName("Tech");
app.setOrganizationDomain("qt.us");
app.setApplicationName("RestoreLayout");
app.setApplicationVersion("1.0");
QDialog dialog;
dialog.setLayout(new QHBoxLayout);
auto splitter = new QSplitter;
splitter->addWidget(new QLabel("Left"));
splitter->addWidget(new QLabel("Right"));
dialog.layout()->addWidget(splitter);
auto accept = new QPushButton("Accept");
accept->connect(accept, &QPushButton::clicked, [&](){
dialog.accept();
});
splitter->addWidget(accept);
auto geom= QSettings().value("Geom").toByteArray();
auto splitterState = QSettings().value("State").toByteArray();
qDebug() << geom;
qDebug() << splitterState;
dialog.restoreGeometry(geom);
splitter->restoreState(splitterState);
dialog.show();
dialog.connect(&dialog, &QDialog::accepted, [&]() {
QSettings().setValue("Geom", dialog.saveGeometry());
QSettings().setValue("State", splitter->saveState());
app.quit();
});
app.exec();
}
Unfortunately, this seems to be an approach, which is not usable in general.
Assume, that there is some arbitrary dialog, that needs to restore its geometry and state. Even worser QSplitter and QDockWidget might be even used in a nested fashion, which is done in our applications.
How can an outside programmer restore the geometry and the state of a arbitrary dialog that might be easily applicable to all possible dialogs?
For saving states of QDockWidget each it must be named: dockWidgetN->setObjectName("dock-widget-N");
But you can save only QMainWindow state for saving states of docks in this window.
You can separatelly save states via QSettings (it's QByteArray) and use some one state for many windows.
See here: How to save state of a dialog in Qt?

QVideoWidget: Video is cut off

I want to play a video in a Qt Application. This is my code so far:
#include <QApplication>
#include <QWidget>
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QUrl>
#include <iostream>
using namespace std;
const int WIDTH = 1280;
const int HEIGHT = 720;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget window;
window.resize(WIDTH, HEIGHT);
window.setWindowTitle("Video Test");
window.show();
QMediaPlayer *player = new QMediaPlayer();
player->setMedia(QUrl::fromLocalFile("/Path/To/Video.mp4"));
QVideoWidget *videoWidget = new QVideoWidget(&window);
player->setVideoOutput(videoWidget);
videoWidget->resize(WIDTH, HEIGHT);
videoWidget->show();
player->play();
return app.exec();
}
The problem: The video is shown and plays back normally, but the video does not resize to fit in the QVideoWidget. The part of the video that is bigger than the widget is cut off.
Thanks in advance!
EDIT: I reduced the code and noticed, that when the application starts the video is cut off, but when I resize the window using the mouse it actually fits to the size:
#include <QApplication>
#include <QWidget>
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QUrl>
#include <iostream>
using namespace std;
const int WIDTH = 1280;
const int HEIGHT = 720;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMediaPlayer *player = new QMediaPlayer();
QVideoWidget *videoWidget = new QVideoWidget();
player->setVideoOutput(videoWidget);
player->setMedia(QUrl::fromLocalFile("/Path/To/Video.mp4"));
player->play();
videoWidget->resize(WIDTH/3, HEIGHT/3);
videoWidget->show();
return app.exec();
}
For anyone in 2016, QVideoWidget is still busted. However, use a QGraphicsView widget, which holds a scene graph, and add a single QGraphicsVideoItem to the scene graph. Seems to work...
well, except that it's not exactly centered. and there's a 1px border on the left. and it hangs going into full screen most of the time. and I get errors like "updateVideoFrame called without AVPlayerLayer (which shouldn't happen". Progress!
.. oh, and it takes up about 10x the cpu too.
You know what does work, and works great? GStreamer. Thank you, gstreamer. Even integrating it in python/qt works fabulously.
I ran into a similar problem in PyQt5. I worked around it by setting the geometry of the QVideoWidget to its current geometry before playing the video. I am guessing something in the resizeEvent signal must handle the scaling of the media and isn't triggered when initialized.
After many hours of looking for the error, I think this is a bug in Qt on OSX, as I watched this YouTube video https://www.youtube.com/watch?v=tGKmQy-VBX0 and tried out the code.
In the video scaling works fine, but on my machine not.
After playing, I resized the QVideoWidget by 1 and then resized to original size.
Definitely "fudge", but this works for me until I find a real solution:
(working with PyQt5 and High Sierra)
s1 = self.MediaFrame.size() # QVideoWidget
s2 = s1 + QSize(1, 1)
self.MediaPlayer.play() # QMediaPlayer
self.MediaFrame.resize(s2) # enlarge by one pixel
self.MediaFrame.resize(s1) # return to original size
Usually the scale mode dictates how the video fills the widget.
The scale mode FitInView will force the video to fill the view keeping aspect ratio.
However, this scale mode should be the default. You can try to set it manually:
QVideoWidget *videoWidget = new QVideoWidget(&window);
videoWidget->setScaleMode(Phonon::VideoWidget::FitInView);
player->setVideoOutput(videoWidget);
If you still searching for a solution to this, QVideoWidget class has setAspectRatioMode method. Use this to scale frames of video to fit your widget area.

Qt MDI Area subwindow construction after show->() fails to update window size

I have a program that constructs a subwindow in a QT MDI Area, shows it, and later updates the contents of this window.
The program is large, but I have tried (and hopefully succeded) to reproduce the problem in the little program below.
In the middle of the program, there is the line commented "if this one is commented, then OK!".
As it says, if this line is commented, then the whole subwindow contents is created before Qt goes into the event loop and everything is fine...
BUT: is the line is there, then the contents of the MDI subwindow is constructed in 2 steps (as in my original program), but only the contents built in the first step shows up!
Run the little program below...
...if you now grab the sub-window (with the mouse), to move it, then Qt suddentely realize the size is wrong and updates the subwindow contents...
I could not figure out any way to get that correctly from start.
I am running Qt 4.8.0-7 on linux (Fedora).
#include <QApplication>
#include <QtCore>
#include <QMainWindow>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <stdlib.h>
QMdiArea* g1;
QGroupBox* g1a;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow* main_window = new(QMainWindow);
main_window->setObjectName("main_window");
main_window->resize(200, 200);
main_window->setWindowTitle("Hello");
g1 = new QMdiArea(main_window);
main_window->setCentralWidget(g1);
main_window->show();
g1a = new QGroupBox("G1A", g1);
QVBoxLayout *g1a_l = new QVBoxLayout(g1a);
g1a_l->addWidget(new QLabel("LABEL1"));
QMdiSubWindow *sub_window = new QMdiSubWindow(g1);
sub_window->setWidget(g1a);
sub_window->setAttribute(Qt::WA_DeleteOnClose);
app.processEvents(); //If this one is commented, then OK!
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label2"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label3"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label4"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label5"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label6"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label7"));
sub_window->show(); //How to I get that to recaclulate the size of its contents?
return app.exec();
}
Thanks for helping!
Use adjustSize method:
sub_window->show(); // here or after adjustSize
sub_window->adjustSize();
It will adjust the size to fit sub_window contents (from documentation).

How to find global position of text cursor?

I would like to execute a QMenu object at the position of text cursor in a QPlainTextEdit. My problem is that QTextCursor is only define by its position in the Text (index of the character).
How can I find global position of the QTextCursor? Should I use an other object than QTextCursor in order to find the position of the text cursor where I want to open my QMenu?
Thank you by advance.
I've never tried myself, but doesn't QPlainTextEdit::cursorRect() work? It should give you position of the cursor in viewport coordinates. You can then get the viewport using viewport() and map the local position to global using viewport()->mapToGlobal().
I have found similar query to your in some online forum and here's someone suggested the output as
Note: Reference from http://www.unix.com/unix-linux-applications/81388-read-position-mouse-cursor.html, Author of below posting is daggilli, registered user of UNIX online forums. Credit of below posting in its complete form goes to daggilli.
This is the complete code for a Qt application I threw together in about ten minutes (called crosshair) which displays the current mouse coordinates in a window. You might be able to pull enough out of it to be useful. This is Qt 3.1, but Qt 4 is not a great deal different. You will need the Qt development libraries, not just the runtimes. The code comprises two files, crosshair.h and crosshair.cpp.
crosshair.h:
Code:
#ifndef CROSSHAIR_H
#define CROSSHAIR_H
#include <qwidget.h>
#include <qstring.h>
#include <qlabel.h>
#include <qevent.h>
class Crosshair : public QLabel
{
Q_OBJECT
public:
Crosshair(QWidget *parent=0);
protected:
void mousePressEvent(QMouseEvent *);
private:
QTimer *timer;
private slots:
void timerfire();
};
#endif
crosshair.cpp:
Code:
#include <qapplication.h>
#include <qpushbutton.h>
#include <qtimer.h>
#include <qcursor.h>
#include <iostream>
#include "crosshair.h"
using namespace std;
int main(int argc,char **argv)
{
QApplication a(argc,argv);
Crosshair mousepos;
a.setMainWidget(&mousepos);
mousepos.show();
return a.exec();
}
Crosshair::Crosshair(QWidget *parent) : QLabel(parent)
{
setIndent(20);
resize(100,30);
move(1200,200);
setText("0,0");
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timerfire()));
timer->start(50,false);
}
void Crosshair::mousePressEvent(QMouseEvent *)
{
qApp->quit();
}
void Crosshair::timerfire()
{
QPoint p=QCursor::pos();
this->setText(QString().sprintf("%d,%d",p.x(),p.y()));
}
To build this, put both files in a directory called crosshair. cd to that directory and type
Code:
qmake -project
qmake
make
This does nothing more complex than inherit from a QLabel, set a timer to run 20x a second, grab the current cursor coordinates and write them into the label's text. Clicking in the window closes it. I use it for fixing up alignment bugs in JavaScript when I'm laying out objects.
You could open a file in the Crosshair class's constructor to store your data, and use gettimeofday(2) to get a timestamp. Nothing says Qt has to run in GUI mode (you can tell it explicitly not to in the QApplication constructor).
Qt from Trolltech: http://doc.trolltech.com

Resources