QWidget::geometry() vs. QWidget::frameGeometry() - qt

Although Qt's docs indicate that these two functions are different (the first doesn't include the frame) no matter what widget I choose - including the main window of my application - someWidget->frameGeometry().height() always returns the same value as someWidget->geometry.height().
What am I missing here?

I think, you don't give enough time to widget to be painted. There is little example:
#include <QApplication>
#include <QMainWindow>
#include <QDebug>
class MainWindow : public QMainWindow
{
public:
MainWindow() {
startTimer(500);
}
void timerEvent(QTimerEvent *e) {
// Here values are different
qDebug() << geometry().height() << frameGeometry().height();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
// Here values are equals
qDebug() << mainWin.geometry().height() << mainWin.frameGeometry().height();
return app.exec();
}
First debug output will produce the same values for geometry and frameGeometry, but the second (in timerEvent) will produce different.

The QWidget class cannot have a frame. For example, QWidget doesn't have a frame, but QFrame has a frame.

if QWidget is toplevel window then you can see borders and title bar around it. We call it frame or decoration frame and frameGeometry() returns exactly that: window size and position which includes OS decorations.On the other side geometry() returs QWidget inner rect which is available for other child controls or painting.See http://doc.qt.io/qt-4.8/application-windows.html#window-geometry for more details.Toplevel geometry() / frameGeometry() differs if our window is not frameless or fullscreen ... or we are talking about some frameless window manager under x11.

this is an old post, but that could help those searching for the same problem.
Just call
adjustSize();
before prompting for some geometry attributes

As user fasked notes, frameGeometry() may not include the frame margins early in the window creation lifecycle. I have found that the following code works in some situations where calling frameGeometry() does not.
QMargins frameMargins;
QWindow *window = widget->windowHandle();
if (window) {
window->create();
frameMargins = window->frameMargins();
}
QRect myFrameGeometry = widget->geometry().adjusted(
-frameMargins.left(), -frameMargins.top(),
frameMargins.right(), frameMargins.bottom());

Related

QtQuick 2.0 get cap height of font

In QML (QtQuick 2.0), FontMetrics provides every info about a font's size except its cap height. I really need to find out the cap height of a font for a program (it even provides xHeight but not the cap height!!). Is there a mathematical relation between the x height and cap height? If not, is there any other way of finding the cap height of a font?
Please help! I actually tried searching for all possible solutions but couldn't find anything!
The QFontMetricsF has capHeight method.
https://doc.qt.io/qt-5/qfontmetricsf.html#capHeight
May be you can expose from C++ as said below. If that works, QFontMetricsF has much better interface which you can use.
The below code is hand written (syntax or compiler errors will be there). But gives you an idea.
//EXPOSE THE INFORMATION FROM C++
class fontDetails : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal capHeight READ GetCapHeight CONSTANT)
public:
qreal GetCapHeight() const {
return QFontMetricsF(<<YOUR FONT>>).capHeight();
}
};
//SET THE CONTEXT
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQuickView view;
fontDetails fontdetails;
view.engine()->rootContext()->setContextProperty("fontdetails", &fontdetails);
view.setSource(QUrl::fromLocalFile("<<YOUR QML>>.qml"));
view.show();
return app.exec();
}
And then consume in QML
Label {
text: fontdetails.GetCapHeight()
}

How to continue text editing after formatting changes of QGraphicsTextItem?

I am trying to make changes (font changes) to a QGraphicsTextItem that is editable.
I am trying to change formatting of fragments of text, or the formatting applied at typing point (if I set text bold, the text I type after that action at cursor position would be bold).
Setting formatting for text fragments works - but I can't find a way to return the focus correctly to the item.
I can show the caret at the right position, but I can't type in the box unless I actually click in box (even though it seems hat I should be able to).
Simple sample (for some reason it crashes on closing program but I don't care about that since I am testing the text class, not the main program):
header: mytextitem.h
#include <QGraphicsTextItem>
class MyTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
MyTextItem();
~MyTextItem() {}
public slots:
void setItemBold(const int b);
};
mytextitem.cpp
#include "mytextitem.h"
#include <QTextCursor>
MyTextItem::MyTextItem()
{
setPlainText("ABCD");
setFont(QFont("Arial", 20));
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
setTextInteractionFlags(Qt::TextEditorInteraction);
}
void MyTextItem::setItemBold(const int b)
{
int _weight = (b != 0) ? QFont::Bold : QFont::Normal;
QTextCursor _cursor = textCursor();
//int p = _cursor.position(); // this won't help
QTextCharFormat _format = _cursor.charFormat();
_format.setFontWeight(_weight);
_cursor.setCharFormat(_format);
//_cursor.setPosition(p, QTextCursor::KeepAnchor); // makes no difference on allowing me to type, but I can make the cursor move
//_cursor.movePosition(QTextCursor::NoMove, QTextCursor::KeepAnchor, 0); // makes no difference but I just thought some action might
setTextCursor(_cursor);
setFocus(Qt::MouseFocusReason);
// grabKeyboard(); // does nothing
}
main.cpp
#include <QApplication>
#include <QGraphicsView>
#include <QGridLayout>
#include <QtWidgets>
#include <QCheckBox>
#include "mytextitem.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene(-20, -20, 150, 100);
QGraphicsView view(&scene);
QWidget widget;
QGridLayout layout(&widget);
layout.addWidget(&view, 0, 0);
QCheckBox bold("Bold");
layout.addWidget(&bold, 0, 1);
MyTextItem* item = new MyTextItem();
scene.addItem(item);
QObject::connect(&bold, SIGNAL(stateChanged(int)), item, SLOT(setItemBold(int)));
view.ensureVisible(scene.sceneRect());
widget.show();
return a.exec();
}
Editing the item is possible only if clicking in the box.
Assuming that I am already in the box (editing), and I push the "Bold" checkbox, I expect to be able to continue editing - type in the box - but even though I try to
set focus (which places the blinking text cursor in the box),
set position for cursor (I can move it, or select things... that works but I want to keep current position and selection)
grab keyboard - seems to do nothing
nothing seems to return me to the box so I continue typing (with the new font setting).
How can I get the QTextCursor or anything else to allow me to keep editing the text ?
You need to focus on QGraphicsView after format change. You can't focus on QGraphicsTextItem because it isn't QWidget.

How can I get my caret to show up on first double-click action on a QGraphicsTextItem?

I am struggling to get a QGraphicsTextItem to work as a user friendly object.
Since it is very hard to move while being editable, I start it as not editable, and make it editable on double-click. Then turn editing off on losing focus.
My problem is, the caret does not show up on first edit.
I have tried getting the position based on mouse position (as in this question that was trying to solve a different problem), or calling the QGraphicsTextItem::mouseDoubleClickEvent(event);
No matter what I try, the caret is invisible on first action - until I start typing (or if I focus out and back in) - even though it is at the correct location.
After typing, or unselecting and reselecting , the caret shows up in normal location every time.
I have tried to call the QTextCursor in the item constructor, setting its position at 0, made no difference.
What made a difference : one of the 2 situations (neither of which I can do though):
a) start item with Qt::TextEditorInteraction in constructor
b) start item with no moving/focus/selectable flags
I can't do either - because my default state of item must be movable, and that interferes with text editing (as explained at start).
I have tried to disable those flags during editing though... with no effect.
Here is a simple code to demonstrate the problem, I hope somebody can have an idea.
mytextitem.h
#ifndef TEXTITEM_H
#define TEXTITEM_H
#include <QGraphicsTextItem>
class MyTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
MyTextItem();
protected:
virtual void focusOutEvent (QFocusEvent * event);
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event);
};
#endif // TEXTITEM_H
mytextitem.cpp
#include "mytextitem.h"
#include <QTextCursor>
#include <QAbstractTextDocumentLayout>
#include <QGraphicsSceneMouseEvent>
#include <QFont>
MyTextItem::MyTextItem()
{
setHtml("ABCD");
setFont(QFont("Arial", 50));
setTextInteractionFlags(Qt::NoTextInteraction);
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
}
void MyTextItem::focusOutEvent(QFocusEvent *event)
{
Q_UNUSED(event);
setTextInteractionFlags(Qt::NoTextInteraction);
QTextCursor _cursor = textCursor();
_cursor.clearSelection();
setTextCursor(_cursor);
}
void MyTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
setTextInteractionFlags(Qt::TextEditorInteraction);
QGraphicsTextItem::mouseDoubleClickEvent(event); // or the version in linked question
}
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene s;
QGraphicsView view(&s);
s.setSceneRect(-20, -100, 800, 600);
view.show();
MyTextItem* t = new MyTextItem();
s.addItem(t);
return app.exec();
}
I have also considered editing text - not sure if that would work but I think it would affect the undo stack which I will have to deal with soon....
How can I get my caret to show up on first double-click action on the text item ?
(As a user, not seeing a caret would make me uncertain if I can type... even though it works... I would not have confidence in the object if I do not have feedback of my action. That's why I care about this problem.)
I can't explain it... after trying EVERYTHING to get the caret to show, the solution was so simple:
I had to change the order of flags being set, in constructor.
The QGraphicsTextItem flag must be set AFTER setting the QGraphicsItem flags.
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
setTextInteractionFlags(Qt::NoTextInteraction);

QListWidget Drag after scrolling down the list

I am creating A Sortable List in Qt. The Code works perfectly well for Downward Scroll but when i having some issues getting the draggable item after i scroll the list down. I have added some test case screenshot for better understanding
Well this is the test case code
#include <QtGui>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QListWidget *listWidget = new QListWidget;
for(int i=0;i<100;++i){
listWidget->addItem("SongOne");
listWidget->addItem("SongTwo");
listWidget->addItem("SongThree");
listWidget->addItem("SongFour");
listWidget->addItem("SongFive");
}
listWidget->setDragDropMode(QAbstractItemView::InternalMove);
listWidget->setDragEnabled(true);
listWidget->setAcceptDrops(true);
listWidget->setDropIndicatorShown(true);
listWidget->viewport()->setAcceptDrops(true);
listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
listWidget->show();
app.exec();
delete listWidget;
return 0;
}
Thankz for taking the time in reading my post. Do help me if you have any hint on what i am missing out.I think i am missing setting some property. In the main Program(not the test code), i tried rewriting the dragMoveEvent and few more method, but no use.
the problem here is not the drag and drop but the QRect that is created while doing Drag and Drop. In Figure Two the Qrect is Created but not in Figure Four
Try to remove the lines:
listWidget->setDragEnabled(true);
listWidget->setAcceptDrops(true);
listWidget->setDropIndicatorShown(true);
listWidget->viewport()->setAcceptDrops(true);
They may interfer with the "real" Drag'n'Drop system. Reordering is typically handled in an optimized way.
Another solution could be that you subclass QListWidget and get the element's index in the drag event and the other's element's index in the drop event. So you know what to reorder and where it should be placed (before or after the second element's index). The rest should be easy, just takeItem() and insertItem().
Hope I helped you with these two ways ;)
In win7, i was not able to reproduce the same behavior. It just works(even size hint is tweaked to meet your screen shot requirement. :) )
My test code was...
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QListWidget *listWidget = new QListWidget;
const char* titles[] = {
"SongOne%1",
"SongTwo%1",
"SongThree%1",
"SongFour%1",
"SongFive%1",
};
for(int i=0;i<100;++i){
QString title = QString(titles[i%5]).arg(i);
QListWidgetItem* item = new QListWidgetItem(title);
item->setData(Qt::SizeHintRole, QSize(50,100));
listWidget->addItem(item);
}
listWidget->setDragDropMode(QAbstractItemView::InternalMove);
listWidget->setDragEnabled(true);
listWidget->setAcceptDrops(true);
listWidget->setDropIndicatorShown(true);
listWidget->viewport()->setAcceptDrops(true);
listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
listWidget->show();
app.exec();
delete listWidget;
return 0;
}

problem with replacing a background image using signal / slot in qt

i want to make a simple chess program. So far i've made the board using QTableWidget and loaded the piece pictures in the cells of table. Now i wnat to use signal and slot so that when user clicks a cell and then click another cell the piece picture from first cell goes to second cell, But I don't know how to do it.
Note that i don't want these "piece moves" obey the real chess rules. I only wnat to do the picture replacement between two cells . Later i will make them obey the rules.
here is the code. in this code only table's item(0,0) has a picture. can anyone say how to write a code so that when i click that item then click to item(1,1) , picture "1.bmp" goes to background of item(1,1)?
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QHBoxLayout>
#include <QTableWidget>
#include <QHeaderView>
class Table : public QWidget
{
Q_OBJECT
public:
Table(QWidget *parent = 0);
slots:
//??????
};
Table::Table(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *hbox = new QHBoxLayout(this);
QTableWidget *table = new QTableWidget(8 , 8 , this);
table->setFixedSize(900,900);
table->horizontalHeader()->setDefaultSectionSize(100);
table->verticalHeader()->setDefaultSectionSize(100);
table->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
table->verticalHeader()->setResizeMode(QHeaderView::Fixed);
QString fileName = "/1.bmp";
QPixmap pic(fileName);
QBrush brush(pic);
QTableWidgetItem* item = new QTableWidgetItem();
item->setBackground(brush);
table->setItem(0,0,item);
hbox->addWidget(table);
setLayout(hbox);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Table table;
table.show();
return app.exec();
}
There are really two questions here.
The first one regarding signals/slots with QTableWidgetItem, and the second regarding handling mouse clicks on the QTableWidget.
Signals Slots on a QTableWidgetItem
note: I don't recommend doing it this way, read all the way to the bottom*
Using signals and slots requires that the object that emits the signal, have the signal defined in the class definition. Likewise the object that receives a slot, must have that slot declared in the class definition.
You'll notice (on the Qt docs) that QTableWidgetItem doesn't have a signals or slots to set/remove the background brush you are using to draw your picture. So, you will have to subclass QTableWidgetItem, and provide this signals/slots yourself.
Example:
class ChessItem : public QTableWidgetItem
{
// constructor / destructor
// other methods
public slots:
void slotChangeBackground( const QBrush & brush )
{
setBackground( brush );
}
};
Handling Mouse Clicks on the QTableWidget
edit: I removed the event handling paragraph, because using QTableWidget's builtin signals is easier
QTableWidget offers the cell clicked signal:
void QTableWidget::cellClicked ( int row, int column )
So in your Table class add a slot, then connect it the cellClicked signal to it:
// in your Table's constructor:
connect( table, SIGNAL( cellClicked(int, int) ), this, SLOT( slotCellClicked(int,int) ) ) );
// elsewhere...
void slotCellClicked(int row, int column) {
// handle mouse clicking here
}
The problem as I see it is you don't want to just connect any ol signal to slotChangeBackground, because that would change every background. So I suggest not using signals/slots for changing the background, and instead use QTableWidget::itemAt ( int ax, int ay ) in your slotCellClicked(x,y) to retrieve the item at a coordinate, then call setBackground on it.

Resources