Snapping in grid using qt - qt

I have implemented grid in graphicsView using drawBackgroud method. Now I also want to add snap to the grid. By snap I mean that with mouse, you can't have point other than grid points. My code to grid drawn is as follows:
void CadGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
{
const int gridSize = 50;
const int realLeft = static_cast<int>(std::floor(rect.left()));
const int realRight = static_cast<int>(std::ceil(rect.right()));
const int realTop = static_cast<int>(std::floor(rect.top()));
const int realBottom = static_cast<int>(std::ceil(rect.bottom()));
// Draw grid.
const int firstLeftGridLine = realLeft - (realLeft % gridSize);
const int firstTopGridLine = realTop - (realTop % gridSize);
QVarLengthArray<QLine, 100> lines;
for (qreal x = firstLeftGridLine; x <= realRight; x += gridSize)
lines.append(QLine(x, realTop, x, realBottom));
for (qreal y = firstTopGridLine; y <= realBottom; y += gridSize)
lines.append(QLine(realLeft, y, realRight, y));
painter->setPen(QPen(QColor(220, 220, 220), 0.0));
painter->drawLines(lines.data(), lines.size());
// Draw axes.
painter->setPen(QPen(Qt::lightGray, 0.0));
painter->drawLine(0, realTop, 0, realBottom);
painter->drawLine(realLeft, 0, realRight, 0);
}
Please help me solve the problem and complete the task.
I tried to do it using itemChange method but nothing happened:
My code to it is as follows:
snap.cpp
#include "snap.h"
#include <QApplication>
Snap::Snap(const QRect& rect, QGraphicsItem* parent,
QGraphicsScene* scene):
QGraphicsRectItem(QRectF())
{
setFlags(QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemSendsGeometryChanges);
}
void Snap::mousePressEvent(QGraphicsSceneMouseEvent *event){
offset = pos() - computeTopLeftGridPoint(pos());
QGraphicsRectItem::mousePressEvent(event);
}
QVariant Snap::itemChange(GraphicsItemChange change,
const QVariant &value)
{
if (change == ItemPositionChange && scene()) {
QPointF newPos = value.toPointF();
if(QApplication::mouseButtons() == Qt::LeftButton &&
qobject_cast<CadGraphicsScene*> (scene())){
QPointF closestPoint = computeTopLeftGridPoint(newPos);
return closestPoint+=offset;
}
else
return newPos;
}
else
return QGraphicsItem::itemChange(change, value);
}
QPointF Snap::computeTopLeftGridPoint(const QPointF& pointP){
CadGraphicsScene* customScene = qobject_cast<CadGraphicsScene*> (scene());
int gridSize = customScene->getGridSize();
qreal xV = floor(pointP.x()/gridSize)*gridSize;
qreal yV = floor(pointP.y()/gridSize)*gridSize;
return QPointF(xV, yV);
}
snap.h
#ifndef SNAP_H
#define SNAP_H
#include <QGraphicsRectItem>
#include "cadgraphicsscene.h"
class Snap : public QGraphicsRectItem
{
public:
Snap(const QRect& rect, QGraphicsItem* parent,
QGraphicsScene* scene);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
QVariant itemChange(GraphicsItemChange change,
const QVariant &value);
private:
QPointF offset;
QPointF computeTopLeftGridPoint(const QPointF &pointP);
};
#endif // SNAP_H
Please help me out to snap to grid.

Related

How to connect a QRadioButton of a QTableWidget cell with another QTableWidget cell using an arrow?

I have a QListWidget and a QGraphicsView both subclassed to overwrite some of their members. I prepared a minimal verifiable example showing the problem I have here
From the QListWidget I can drag and drop specific field (represented by a QTableWidget) and drop them into a QGraphicsView and in order to do that I am using a QGraphicsProxyWidget approach as shown below.
The Problem
Now, how do I connect 2 QRadioButton inside cell of a QTableWidget with another cell of another QTableWidget?
It is important to mention that the green QGraphicsRectItem it is used to move around the QTableWidget as well as adjusting its dimension.
Below the result I was able to arrive so far:
And below the expected result I have been trying to achieve:
Below the most important part of the code:
scene.h
#ifndef SCENE_H
#define SCENE_H
#include <QGraphicsScene>
class Scene : public QGraphicsScene
{
public:
Scene(QObject *parent = nullptr);
protected:
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
void dropEvent(QGraphicsSceneDragDropEvent *event);
};
#endif // SCENE_H
scene.cpp
#include "arrow.h"
#include <QGraphicsSceneDragDropEvent>
#include <QMimeData>
#include <QTableWidget>
#include <QGraphicsProxyWidget>
#include <QVBoxLayout>
#include <QMetaEnum>
#include <QEvent>
#include <QSizeGrip>
#include <QRadioButton>
Scene::Scene(QObject *parent)
{
setBackgroundBrush(Qt::lightGray);
}
void Scene::dragEnterEvent(QGraphicsSceneDragDropEvent *event) {
if (event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->setAccepted(true);
}
void Scene::dragMoveEvent(QGraphicsSceneDragDropEvent *event) {
if (event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->setAccepted(true);
}
void Scene::dropEvent(QGraphicsSceneDragDropEvent *event) {
QByteArray encoded =
event->mimeData()->data("application/x-qabstractitemmodeldatalist");
QDataStream stream(&encoded, QIODevice::ReadOnly);
QStringList rosTables;
QString newString;
while (!stream.atEnd()) {
int row, col;
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
rosTables << roleDataMap[Qt::DisplayRole].toString();
}
for (const QString &tableType : rosTables) {
if (tableType == "Images") {
QPoint initPos(0, 0);
auto *wgt = new CustomTableWidget;
auto *proxyControl = addRect(0, 0, 0, 0, QPen(Qt::black),
QBrush(Qt::darkGreen));
auto *sizeGrip = new QSizeGrip(wgt);
auto *layout = new QHBoxLayout(wgt);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(sizeGrip, 0, Qt::AlignRight | Qt::AlignBottom);
connect(wgt, &CustomTableWidget::sizeChanged, [wgt, proxyControl](){
proxyControl->setRect(wgt->geometry().adjusted(-10, -10, 10, 10));
});
wgt->setColumnCount(4);
wgt->setRowCount(4);
for (int ridx = 0; ridx < wgt->rowCount(); ridx++) {
for (int cidx = 0; cidx < wgt->columnCount(); cidx++) {
QRadioButton *radio1, *radio2;
auto* item = new QTableWidgetItem();
item->setText(QString("%1").arg(ridx));
wgt->setItem(ridx,cidx,item);
radio1 = new QRadioButton;
radio2 = new QRadioButton;
wgt->setCellWidget(cidx, 0, radio1);
wgt->setCellWidget(cidx, 3, radio2);
Arrow *arrow = new Arrow;
}
}
auto *const proxy = addWidget(wgt);
proxy->setPos(initPos.x(), initPos.y()
+ proxyControl->rect().height());
proxy->setParentItem(proxyControl);
proxyControl->setPos(initPos.x(), initPos.y());
proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);
proxyControl->setRect(wgt->geometry().adjusted(-10, -10, 10, 10));
}
}
}
diagramitem.h
#ifndef DIAGRAMITEM_H
#define DIAGRAMITEM_H
#include <QGraphicsPolygonItem>
class Arrow;
class DiagramItem : public QGraphicsPolygonItem
{
public:
DiagramItem(QMenu *contextMenu, QGraphicsItem *parent = Q_NULLPTR);
void removeArrow(Arrow *arrow);
void removeArrows();
void addArrow(Arrow *arrow);
QPixmap image() const;
protected:
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
private:
QPolygonF myPolygon;
QList<Arrow*> arrows;
QMenu *myContextMenu;
};
#endif // DIAGRAMITEM_H
diagramitem.cpp
#include "diagramitem.h"
#include "arrow.h"
#include <QPainter>
#include <QGraphicsScene>
#include <QGraphicsSceneContextMenuEvent>
#include <QMenu>
DiagramItem::DiagramItem(QMenu *contextMenu, QGraphicsItem *parent) : QGraphicsPolygonItem(parent)
{
myContextMenu = contextMenu;
setPolygon(myPolygon);
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
}
void DiagramItem::removeArrow(Arrow *arrow)
{
int index = arrows.indexOf(arrow);
if (index != -1)
arrows.removeAt(index);
}
void DiagramItem::removeArrows()
{
foreach (Arrow *arrow, arrows) {
arrow->startItem()->removeArrow(arrow);
arrow->endItem()->removeArrow(arrow);
scene()->removeItem(arrow);
delete arrow;
}
}
void DiagramItem::addArrow(Arrow *arrow)
{
arrows.append(arrow);
}
void DiagramItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
scene()->clearSelection();
setSelected(true);
myContextMenu->exec(event->screenPos());
}
QVariant DiagramItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == QGraphicsItem::ItemPositionChange) {
foreach (Arrow *arrow, arrows) {
arrow->updatePosition();
}
}
return value;
}
arrow.h
#ifndef ARROW_H
#define ARROW_H
#include <QGraphicsLineItem>
#include "diagramitem.h"
class Arrow : public QGraphicsLineItem
{
public:
enum { Type = UserType + 4 };
Arrow(DiagramItem *startItem, DiagramItem *endItem,
QGraphicsItem *parent = nullptr);
DiagramItem *startItem() const { return myStartItem; }
DiagramItem *endItem() const { return myEndItem; }
QPainterPath shape() const override;
void setColor(const QColor &color) {
myColor = color;
}
int type() const override { return Type; }
void updatePosition();
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
QColor myColor;
DiagramItem *myStartItem;
DiagramItem *myEndItem;
QPolygonF arrowHead;
};
#endif // ARROW_H
arrow.cpp
#include "arrow.h"
#include <QPen>
#include <QPainter>
#include "qmath.h"
Arrow::Arrow(DiagramItem *startItem, DiagramItem *endItem, QGraphicsItem *parent) : QGraphicsLineItem(parent)
{
myStartItem = startItem;
myEndItem = endItem;
myColor = Qt::GlobalColor::black;
setPen(QPen(myColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
setFlag(QGraphicsItem::ItemIsSelectable, true);
}
QPainterPath Arrow::shape() const
{
QPainterPath path = QGraphicsLineItem::shape();
path.addPolygon(arrowHead);
return path;
}
void Arrow::updatePosition()
{
QLineF line(mapFromItem(myStartItem, 0, 0), mapFromItem(myEndItem, 0, 0));
setLine(line);
}
void Arrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (myStartItem->collidesWithItem(myEndItem))
return;
QPen myPen = pen();
myPen.setColor(myColor);
qreal arrowSize = 20;
painter->setPen(myPen);
painter->setBrush(myColor);
QLineF centerLine(myStartItem->pos(), myEndItem->pos());
QPolygonF endPolygon = myEndItem->polygon();
QPointF p1 = endPolygon.first() + myEndItem->pos();
QPointF p2;
QPointF intersectPoint;
QLineF polyLine;
for (int i = 1; i < endPolygon.count(); ++i) {
p2 = endPolygon.at(i) + myEndItem->pos();
polyLine = QLineF(p1, p2);
QLineF::IntersectType intersectType =
polyLine.intersect(centerLine, &intersectPoint);
if (intersectType == QLineF::BoundedIntersection)
break;
p1 = p2;
}
setLine(QLineF(intersectPoint, myStartItem->pos()));
double angle = std::atan2(-line().dy(), line().dx());
QPointF arrowP1 = line().p1() + QPointF(sin(angle + M_PI / 3) * arrowSize,
cos(angle + M_PI / 3) * arrowSize);
QPointF arrowP2 = line().p1() + QPointF(sin(angle + M_PI - M_PI / 3) * arrowSize,
cos(angle + M_PI - M_PI / 3) * arrowSize);
arrowHead.clear();
arrowHead << line().p1() << arrowP1 << arrowP2;
painter->drawLine(line());
painter->drawPolygon(arrowHead);
if (isSelected()) {
painter->setPen(QPen(myColor, 1, Qt::DashLine));
QLineF myLine = line();
myLine.translate(0, 4.0);
painter->drawLine(myLine);
myLine.translate(0,-8.0);
painter->drawLine(myLine);
}
}
What I have done so far to solve the problem:
1) I came across this post which was useful to understand the initial idea on how to do that, but it didn't really provide a way, or an implementation idea on how to best proceed
2) I researched the official documentation and before asking this question I went through the whole Diagram Scene example provided and understood how to create an Arrow object. The documentation about that was very good and made me understand how the graphics line item has to be formed.
However I was not able (coming back to my example) how to make "aware" the QRadioButton that I am trying to use its center as starting point for an arrow ad, therefore, how do I make "aware" the destination QRadioButton in another cell that it has to be connected there?
Below a particular of what I mean:
So basically the start point of the QRadioButton change color (or style) and the arrival point also change color.
3) I thought that the Arrow object has to be created inside the subclassed QGraphicsScene since it already handles the mouse events.
4) Despite what I tried so far I could not find any other useful help. Although I am still investigating how to do that.
If anyone has ever been in the same situation please provide guidance on how to better proceed to solve this problem and find a solution to this issue.
Solution
When a start and end radio buttons are checked, you need to create the arrow with those buttons as start and end nodes, e.g.:
void Backend::onInputRadioButton(bool checked)
{
m_endNode = checked ? static_cast<QRadioButton *>(sender()) : nullptr;
if (m_startNode && m_endNode)
m_scene->addItem(new ArrowItem(m_startNode, m_endNode));
}
Then you need to connect the signal of the top-most graphics items, which hold the tables, with the updatePosition slot of the ArrowItem, e.g.:
connect(m_startItem->property("item").value<MovableItem *>(),
&MovableItem::itemMoved, this, &ArrowItem::updatePosition);
connect(m_endItem->property("item").value<MovableItem *>(),
&MovableItem::itemMoved, this, &ArrowItem::updatePosition);
Note: I am using a property to hold a reference to the container item.
Finally, you need to update the arrow line, e.g.:
void ArrowItem::updatePosition()
{
QPointF offset(7, 15);
QPointF p1 = m_startItem->property("item").value<MovableItem *>()->pos()
+ m_startItem->parentWidget()->mapToParent(m_startItem->pos())
+ offset;
QPointF p2 = m_endItem->property("item").value<MovableItem *>()->pos()
+ m_endItem->parentWidget()->mapToParent(m_endItem->pos())
+ offset;
setLine(QLineF(p1, p2));
}
Example
I have dared to suggest improvements in your code. You can find the complete example I wrote for you on GitHub.
Result
The provided example produces the following result:
Note: The arrow heads are missing. Check once again the Diagram Scene Example to get an idea of how to draw them.

QCharts Crop to Rectangle and Use Horizontal Scroll

am trying to implement a custom graph going off the QtCharts Callout example. I want to restrict the selection of the chart to a specific area and make it possible to scroll horizontally while still displaying the Axis Values.
the classes i am using are below
callout.cpp
callout.h
main.cpp
view.cpp
view.h
here is an example of what i mean
say i want the selection region point1 = (5,0) point2 = (15,8) and the region is a QRect(point1,point2)
All points in the graph should be rendered but I want to be able to scroll sideways and keep the y_axis in view.
One possible solution is to override the mousePressEvent and mouseMoveEvent methods to apply the scroll, and correct using the axes ranges if necessary:
#include <QtWidgets>
#include <QtCharts>
#include <algorithm>
QT_CHARTS_USE_NAMESPACE
class ChartView: public QChartView{
public:
using QChartView::QChartView;
void setRange(qreal xmin, qreal xmax, qreal ymin, qreal ymax){
if(!chart()) return;
if(QValueAxis *xaxis = qobject_cast<QValueAxis *>(chart()->axes(Qt::Horizontal).first())){
xaxis->setRange(xmin, xmax);
}
if(QValueAxis *yaxis = qobject_cast<QValueAxis *>(chart()->axes(Qt::Vertical).first())){
yaxis->setRange(ymin, ymax);
}
}
void setLimits(qreal min, qreal max, Qt::Orientation orientation){
m_limit_min = min;
m_limit_max = max;
m_orientation = orientation;
}
protected:
void mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && chart())
m_lastMousePos = mapToScene(event->pos());
QGraphicsView::mousePressEvent(event);
}
void mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton && chart()){
QPointF newValue = mapToScene(event->pos());
QPointF delta = newValue - m_lastMousePos;
if(m_orientation == Qt::Horizontal)
chart()->scroll(-delta.x(), 0);
else
chart()->scroll(0, -delta.y());
if(QValueAxis * axis = qobject_cast<QValueAxis *>(chart()->axes(m_orientation).first()) ){
qreal deltaX = axis->max() - axis->min();
if(axis->min() < m_limit_min){
axis->setRange(m_limit_min, m_limit_min + deltaX);
}
else if(axis->max() > m_limit_max){
axis->setRange(m_limit_max - deltaX, m_limit_max);
}
}
m_lastMousePos = newValue;
}
QGraphicsView::mouseMoveEvent(event);
}
private:
QPointF m_lastMousePos;
qreal m_limit_min;
qreal m_limit_max;
Qt::Orientation m_orientation;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ChartView chartView;
chartView.setRenderHint(QPainter::Antialiasing);
chartView.resize(640, 480);
QLineSeries *series = new QLineSeries();
series->append(0, 6);
series->append(2, 4);
series->append(3, 8);
series->append(7, 4);
series->append(10, 5);
*series << QPointF(11, 1) << QPointF(13, 3) << QPointF(17, 6) << QPointF(18, 3) << QPointF(20, 2);
QChart *chart = chartView.chart();
chart->legend()->hide();
chart->addSeries(series);
chart->createDefaultAxes();
chartView.show();
chartView.setRange(5, 15, 0, 8);
chartView.setLimits(0, 20, Qt::Horizontal);
return a.exec();
}

Snapping to grid doesn't work

I am trying to do snapping on grid such that whatever I will draw it should take only gridpoints and no other points. I have made grid in cadgraphicsscene.cpp and made different class for snapping.
My grid is made as follows:
cadgraphicscene.cpp
void CadGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
{
const int gridSize = 50;
const int realLeft = static_cast<int>(std::floor(rect.left()));
const int realRight = static_cast<int>(std::ceil(rect.right()));
const int realTop = static_cast<int>(std::floor(rect.top()));
const int realBottom = static_cast<int>(std::ceil(rect.bottom()));
// Draw grid.
const int firstLeftGridLine = realLeft - (realLeft % gridSize);
const int firstTopGridLine = realTop - (realTop % gridSize);
QVarLengthArray<QLine, 100> lines;
for (qreal x = firstLeftGridLine; x <= realRight; x += gridSize)
lines.append(QLine(x, realTop, x, realBottom));
for (qreal y = firstTopGridLine; y <= realBottom; y += gridSize)
lines.append(QLine(realLeft, y, realRight, y));
painter->setPen(QPen(QColor(220, 220, 220), 0.0));
painter->drawLines(lines.data(), lines.size());
// Draw axes.
painter->setPen(QPen(Qt::lightGray, 0.0));
painter->drawLine(0, realTop, 0, realBottom);
painter->drawLine(realLeft, 0, realRight, 0);
}
My snap class looks as follows:
snap.cpp
#include "snap.h"
#include <QApplication>
Snap::Snap(const QRect& rect, QGraphicsItem* parent,
QGraphicsScene* scene):
QGraphicsRectItem(QRectF())
{
setFlags(QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemSendsGeometryChanges);
}
void Snap::mousePressEvent(QGraphicsSceneMouseEvent *event){
offset = pos() - computeTopLeftGridPoint(pos());
QGraphicsRectItem::mousePressEvent(event);
}
QVariant Snap::itemChange(GraphicsItemChange change,
const QVariant &value)
{
if (change == ItemPositionChange && scene()) {
QPointF newPos = value.toPointF();
if(QApplication::mouseButtons() == Qt::LeftButton &&
qobject_cast<CadGraphicsScene*> (scene())){
QPointF closestPoint = computeTopLeftGridPoint(newPos);
return closestPoint+=offset;
}
else
return newPos;
}
else
return QGraphicsItem::itemChange(change, value);
}
QPointF Snap::computeTopLeftGridPoint(const QPointF& pointP){
CadGraphicsScene* customScene = qobject_cast<CadGraphicsScene*> (scene());
int gridSize = customScene->getGridSize();
qreal xV = floor(pointP.x()/gridSize)*gridSize;
qreal yV = floor(pointP.y()/gridSize)*gridSize;
return QPointF(xV, yV);
}
snap.h
#ifndef SNAP_H
#define SNAP_H
#include <QGraphicsRectItem>
#include "cadgraphicsscene.h"
class Snap : public QGraphicsRectItem
{
public:
Snap(const QRect& rect, QGraphicsItem* parent,
QGraphicsScene* scene);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
QVariant itemChange(GraphicsItemChange change,
const QVariant &value);
private:
QPointF offset;
QPointF computeTopLeftGridPoint(const QPointF &pointP);
};
#endif // SNAP_H
But nothing happened, no snapping is done. Can you please help me in the above?
One of the problems is that you pass QRect() to the QGraphicsRectItem constructor in the initialization list of Snap class. This means it will have 0 width and height. Instead pass the same QRect object that you pass to your snap constructor:
Snap::Snap(const QRect& rect, QGraphicsItem* parent, QGraphicsScene* scene) :
QGraphicsRectItem(rect)
You also don't seem to use the parent and the scene arguments so you might as well leave them out:
Snap::Snap(const QRect& rect) :
QGraphicsRectItem(rect)
Or if you plan to use the parent for something then you can set a default value to 0 in the declaration:
Snap(const QRect& rect, QGraphicsItem* parent = 0);
Then pass them both to the base class constructor:
Snap::Snap(const QRect& rect, QGraphicsItem* parent) :
QGraphicsRectItem(rect, parent)
snap.h
#ifndef SNAP_H
#define SNAP_H
#include <QGraphicsRectItem>
class Snap : public QGraphicsRectItem
{
public:
Snap(const QRect &rect, QGraphicsItem *parent = 0);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
QVariant itemChange(GraphicsItemChange change,
const QVariant &value);
private:
QPointF offset;
QPointF computeTopLeftGridPoint(const QPointF &pointP);
};
#endif // SNAP_H
snap.cpp
#include "snap.h"
#include <QDebug>
#include <qmath.h>
Snap::Snap(const QRect& rect, QGraphicsItem* parent) :
QGraphicsRectItem(rect, parent)
{
setFlags(QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemSendsGeometryChanges);
}
void Snap::mousePressEvent(QGraphicsSceneMouseEvent *event){
offset = pos() - computeTopLeftGridPoint(pos());
QGraphicsRectItem::mousePressEvent(event);
}
QVariant Snap::itemChange(GraphicsItemChange change,
const QVariant &value)
{
qDebug()<<"inside itemChange";
if (change == ItemPositionChange && scene())
{
QPointF newPos = value.toPointF();
QPointF closestPoint = computeTopLeftGridPoint(newPos);
return closestPoint+=offset;
}
else
return QGraphicsItem::itemChange(change, value);
}
QPointF Snap::computeTopLeftGridPoint(const QPointF& pointP){
int gridSize = 100;
qreal xV = qFloor(pointP.x()/gridSize)*gridSize;
qreal yV = qFloor(pointP.y()/gridSize)*gridSize;
return QPointF(xV, yV);
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsView>
#include <QLayout>
#include "snap.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
centralWidget()->setLayout(new QVBoxLayout);
QGraphicsView *view = new QGraphicsView(this);
centralWidget()->layout()->addWidget(view);
Snap *snap = new Snap(QRect(0,0,100,100));
view->setScene(new QGraphicsScene);
view->scene()->addItem(snap);
}
MainWindow::~MainWindow()
{
delete ui;
}

How to extend QML Rectangle in C++

When I want to create a new Qt Quick Item in C++ in I extend QQuickItem. It happens that I want my new item to have the same basic properties of a Rectangle. Is there any class I can extend to have a Rectangle directly?
Rectangle is actually QQuickRectangle, but it is not exported to be used in C++. The header file is QtQuick\private\qquickrectangle_p.h.
Check my version of an AdvancedRectangle that can have a different radius for each corner. I had to re-implement Rectangle's behavior.
advancedrectangle.h
#ifndef ADVANCEDRECTANGLE_H
#define ADVANCEDRECTANGLE_H
#include <QQuickPaintedItem>
#include <QPainter>
#include <QPen>
class AdvancedRectangle : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit AdvancedRectangle(QQuickItem *parent = 0);
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
QColor color() const;
void setColor(QColor color);
Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
qreal radius() const;
void setRadius(qreal r);
Q_PROPERTY(qreal radiusTopLeft READ radiusTopLeft WRITE setRadiusTopLeft NOTIFY radiusTopLeftChanged)
qreal radiusTopLeft() const;
void setRadiusTopLeft(qreal r);
Q_PROPERTY(qreal radiusTopRight READ radiusTopRight WRITE setRadiusTopRight NOTIFY radiusTopRightChanged)
qreal radiusTopRight() const;
void setRadiusTopRight(qreal r);
Q_PROPERTY(qreal radiusBottomRight READ radiusBottomRight WRITE setRadiusBottomRight NOTIFY radiusBottomRightChanged)
qreal radiusBottomRight() const;
void setRadiusBottomRight(qreal r);
Q_PROPERTY(qreal radiusBottomLeft READ radiusBottomLeft WRITE setRadiusBottomLeft NOTIFY radiusBottomLeftChanged)
qreal radiusBottomLeft() const;
void setRadiusBottomLeft(qreal r);
void paint(QPainter *painter);
enum START_ANGELS {
START_E = 0,
START_N = 90,
START_W = 180,
START_S = 270
};
signals:
void colorChanged();
void radiusChanged();
void radiusTopLeftChanged();
void radiusTopRightChanged();
void radiusBottomRightChanged();
void radiusBottomLeftChanged();
public slots:
private:
QColor color_ = QColor(255, 255, 255);
qreal radius_ = 0.0;
qreal radiusTopLeft_ = -1;
qreal radiusTopRight_ = -1;
qreal radiusBottomRight_ = -1;
qreal radiusBottomLeft_ = -1;
private slots:
void onAppearanceChanged();
};
#endif // ADVANCEDRECTANGLE_H
advancedrectangle.cpp
#include "advancedrectangle.h"
AdvancedRectangle::AdvancedRectangle(QQuickItem *parent) :
QQuickPaintedItem(parent)
{
connect(this, SIGNAL(widthChanged()), SLOT(onAppearanceChanged()));
connect(this, SIGNAL(heightChanged()), SLOT(onAppearanceChanged()));
connect(this, SIGNAL(colorChanged()), SLOT(onAppearanceChanged()));
}
QColor AdvancedRectangle::color() const
{
return color_;
}
void AdvancedRectangle::setColor(QColor color)
{
if (color_ == color) return;
color_ = color;
emit colorChanged();
}
qreal AdvancedRectangle::radius() const
{
return radius_;
}
void AdvancedRectangle::setRadius(qreal r)
{
if (r == radius_) return;
radius_ = r;
emit radiusChanged();
}
qreal AdvancedRectangle::radiusTopLeft() const
{
if (radiusTopLeft_ >= 0) return radiusTopLeft_;
else return radius_;
}
void AdvancedRectangle::setRadiusTopLeft(qreal r)
{
if (r == radiusTopLeft_) return;
radiusTopLeft_ = r;
emit radiusTopLeftChanged();
}
qreal AdvancedRectangle::radiusTopRight() const
{
if (radiusTopRight_ >= 0) return radiusTopRight_;
else return radius_;
}
void AdvancedRectangle::setRadiusTopRight(qreal r)
{
if (r == radiusTopRight_) return;
radiusTopRight_ = r;
emit radiusTopRightChanged();
}
qreal AdvancedRectangle::radiusBottomRight() const
{
if (radiusBottomRight_ >= 0) return radiusBottomRight_;
else return radius_;
}
void AdvancedRectangle::setRadiusBottomRight(qreal r)
{
if (r == radiusBottomRight_) return;
radiusBottomRight_ = r;
emit radiusBottomRightChanged();
}
qreal AdvancedRectangle::radiusBottomLeft() const
{
if (radiusBottomLeft_ >= 0) return radiusBottomLeft_;
else return radius_;
}
void AdvancedRectangle::setRadiusBottomLeft(qreal r)
{
if (r == radiusBottomLeft_) return;
radiusBottomLeft_ = r;
emit radiusBottomLeftChanged();
}
void AdvancedRectangle::paint(QPainter *painter)
{
QPen pen(Qt::NoPen);
painter->setPen(pen);
QBrush brush(color_);
painter->setBrush(brush);
painter->setRenderHints(QPainter::Antialiasing, true);
int _width = width();
int _height = height();
QRectF rectangle;
// top-left
rectangle = QRectF(0, 0, 2*radiusTopLeft(), 2*radiusTopLeft());
painter->drawPie(rectangle, START_W * 16, 90 * -1 * 16);
// top-right
rectangle = QRectF(_width-2*radiusTopRight(), 0, 2*radiusTopRight(), 2*radiusTopRight());
painter->drawPie(rectangle, START_N * 16, 90 * -1 * 16);
// bottom-right
rectangle = QRectF(_width-2*radiusBottomRight(), _height-2*radiusBottomRight(), 2*radiusBottomRight(), 2*radiusBottomRight());
painter->drawPie(rectangle, START_E * 16, 90 * -1 * 16);
// bottom-left
rectangle = QRectF(0, _height-2*radiusBottomLeft(), 2*radiusBottomLeft(), 2*radiusBottomLeft());
painter->drawPie(rectangle, START_S * 16, 90 * -1 * 16);
QPointF points[12] = {
QPointF(radiusTopLeft(), 0),
QPointF(radiusTopLeft(), radiusTopLeft()),
QPointF(0, radiusTopLeft()),
QPointF(0, _height-radiusBottomLeft()),
QPointF(radiusBottomLeft(), _height-radiusBottomLeft()),
QPointF(radiusBottomLeft(), _height),
QPointF(_width-radiusBottomRight(), _height),
QPointF(_width-radiusBottomRight(), _height-radiusBottomRight()),
QPointF(_width, _height-radiusBottomRight()),
QPointF(_width, radiusTopRight()),
QPointF(_width-radiusTopRight(), radiusTopRight()),
QPointF(_width-radiusTopRight(), 0)
};
painter->drawPolygon(points, 12);
}
void AdvancedRectangle::onAppearanceChanged()
{
int new_width = width();
int new_height = height();
update(QRect(0, 0, new_width, new_height));
}
Let me know if you need that MIT licensed.

OpenGL QT 4 code does not display QLogo (helloworld example) in QT5

The application compiles and runs with no compiler errors however no Q logo is displayed.
I have taken the QT Logo OpenGL example http://qt.developpez.com/doc/4.7/opengl-hellogl/
and attempted to compile in QT version 5.2.1 (MSVC 2010, 32bit) . I am aware that there is a change in the way OpenGL is used in version 5 from the older version 4. I have modified some of the code from a working GL example and it still does not work. My bet is the problem exists in the QtLogo because I have changed nothing in those files. So I am completely puzzled being a newbie to OpenGL.
I hope to have provided a descent problem statement. Answering this will help so many others unlock the mysteries of QT OpenGL changes. It is so frustrating.
1) QT version 5.2.1 (MSVC 2010, 32bit) - Installed with Qt 5.2.1 for Windows 32-bit (MinGW 4.8, OpenGL, 634 MB) installer
2) Windows 7, tried 32bit and 64bit
3) Intel CPUs (used two different Intel based computers)
4) The application does work correctly in QT version 4
5) The code is available for download http://1drv.ms/1g88ScS
Here is the code:
hellogl.pro
# HELLOGL
#VPATH += ../shared
#INCLUDEPATH += ../shared
QT += core gui opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = hellogl
TEMPLATE = app
SOURCES += main.cpp \
window.cpp \
glwidget.cpp \
qtlogo.cpp
HEADERS += window.h \
glwidget.h \
qtlogo.h
FORMS += window.ui
GLWIDGET.H
// glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
class QtLogo;
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);
~GLWidget();
QSize minimumSizeHint() const;
QSize sizeHint() const;
public slots:
void setXRotation(int angle);
void setYRotation(int angle);
void setZRotation(int angle);
signals:
void xRotationChanged(int angle);
void yRotationChanged(int angle);
void zRotationChanged(int angle);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QtLogo *logo;
int xRot;
int yRot;
int zRot;
QPoint lastPos;
QColor qtGreen;
QColor qtPurple;
};
#endif
qtlogo.h
//qtlogo.h
#ifndef QTLOGO_H
#define QTLOGO_H
//#include <QObject>
//#include <QtOpenGL>
#include <QColor>
#include <GL/gl.h>
//#include <QGLWidget>
//#include <QtWidgets>
#include <QMatrix4x4>
#include <QVector3D>
#include <qmath.h>
class Patch;
class Geometry;
//! [0]
class QtLogo : public QObject
{
public:
QtLogo(QObject *parent, int d = 64, qreal s = 1.0);
~QtLogo();
void setColor(QColor c);
void draw() const;
private:
void buildGeometry(int d, qreal s);
QList<Patch *> parts;
Geometry *geom;
};
//! [0]
#endif // QTLOGO_H
window.h
// window.h
#ifndef WINDOW_H
#define WINDOW_H
//#include <QObject>
//#include <QApplication>
//#include <QHBoxLayout>
//#include <QSpinBox>
//#include <QKeyEvent>
#include <QWidget>
#include <QSlider>
class QSlider;
class GLWidget;
namespace Ui {
class Window;
}
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
~Window();
protected:
void keyPressEvent(QKeyEvent *event);
private:
Ui::Window *ui;
QSlider *createSlider();
GLWidget *glWidget;
QSlider *xSlider;
QSlider *ySlider;
QSlider *zSlider;
};
#endif
glwidget.cpp
// glwidget.cpp
#include <math.h>
#include <QtWidgets>
#include <QtOpenGL>
#include "glwidget.h"
#include "qtlogo.h"
//#include <QColor>
/*
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif
*/
GLWidget::GLWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
logo = 0;
xRot = 0;
yRot = 0;
zRot = 0;
qtGreen = QColor::fromCmykF(0.40, 0.0, 1.0, 0.0);
qtPurple = QColor::fromCmykF(0.39, 0.39, 0.0, 0.0);
}
GLWidget::~GLWidget()
{
}
QSize GLWidget::minimumSizeHint() const
{
return QSize(50, 50); //
}
QSize GLWidget::sizeHint() const
{
return QSize(800, 800);
}
static void qNormalizeAngle(int &angle)
{
while (angle < 0)
angle += 360 * 16;
while (angle > 360 * 16)
angle -= 360 * 16;
}
void GLWidget::setXRotation(int angle)
{
qNormalizeAngle(angle);
if (angle != xRot) {
xRot = angle;
emit xRotationChanged(angle);
updateGL();
}
}
void GLWidget::setYRotation(int angle)
{
qNormalizeAngle(angle);
if (angle != yRot) {
yRot = angle;
emit yRotationChanged(angle);
updateGL();
}
}
void GLWidget::setZRotation(int angle)
{
qNormalizeAngle(angle);
if (angle != zRot) {
zRot = angle;
emit zRotationChanged(angle);
updateGL();
}
}
void GLWidget::initializeGL()
{
qglClearColor(qtPurple.dark());
logo = new QtLogo(this, 64);
logo->setColor(qtGreen.dark());
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_MULTISAMPLE);
static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
}
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0, 0.0, -10.0);
glRotatef(xRot / 16.0, 1.0, 0.0, 0.0);
glRotatef(yRot / 16.0, 0.0, 1.0, 0.0);
glRotatef(zRot / 16.0, 0.0, 0.0, 1.0);
logo->draw();
//logo->setColor(QColor(0,0,0));
}
void GLWidget::resizeGL(int width, int height)
{
int side = qMin(width, height);
glViewport((width - side) / 2, (height - side) / 2, side, side);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
#ifdef QT_OPENGL_ES_1
glOrthof(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
#else
glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
#endif
glMatrixMode(GL_MODELVIEW);
}
void GLWidget::mousePressEvent(QMouseEvent *event)
{
lastPos = event->pos();
}
void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
int dx = event->x() - lastPos.x();
int dy = event->y() - lastPos.y();
if (event->buttons() & Qt::LeftButton) {
setXRotation(xRot + 8 * dy);
setYRotation(yRot + 8 * dx);
} else if (event->buttons() & Qt::RightButton) {
setXRotation(xRot + 8 * dy);
setZRotation(zRot + 8 * dx);
}
lastPos = event->pos();
}
main.cpp
// main.cpp
#include <QtOpenGL>
#include <QtGui>
#include <QApplication>
#include <QDesktopWidget>
#include "window.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window window;
window.resize(window.sizeHint());
int desktopArea = QApplication::desktop()->width() *
QApplication::desktop()->height();
int widgetArea = window.width() * window.height();
if (((float)widgetArea / (float)desktopArea) < 0.75f)
window.show();
else
window.showMaximized();
return app.exec();
}
qtlogo.cpp
// qtlogo.cpp
#include "qtlogo.h"
static const qreal tee_height = 0.311126;
static const qreal cross_width = 0.25;
static const qreal bar_thickness = 0.113137;
static const qreal inside_diam = 0.20;
static const qreal outside_diam = 0.30;
static const qreal logo_depth = 0.10;
static const int num_divisions = 32;
//! [0]
struct Geometry
{
QVector<GLushort> faces;
QVector<QVector3D> vertices;
QVector<QVector3D> normals;
void appendSmooth(const QVector3D &a, const QVector3D &n, int from);
void appendFaceted(const QVector3D &a, const QVector3D &n);
void finalize();
void loadArrays() const;
};
//! [0]
//! [1]
class Patch
{
public:
enum Smoothing { Faceted, Smooth };
Patch(Geometry *);
void setSmoothing(Smoothing s) { sm = s; }
void translate(const QVector3D &t);
void rotate(qreal deg, QVector3D axis);
void draw() const;
void addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n);
void addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d);
GLushort start;
GLushort count;
GLushort initv;
GLfloat faceColor[4];
QMatrix4x4 mat;
Smoothing sm;
Geometry *geom;
};
//! [1]
static inline void qSetColor(float colorVec[], QColor c)
{
colorVec[0] = c.redF();
colorVec[1] = c.greenF();
colorVec[2] = c.blueF();
colorVec[3] = c.alphaF();
}
void Geometry::loadArrays() const
{
glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
glNormalPointer(GL_FLOAT, 0, normals.constData());
}
void Geometry::finalize()
{
// TODO: add vertex buffer uploading here
// Finish smoothing normals by ensuring accumulated normals are returned
// to length 1.0.
for (int i = 0; i < normals.count(); ++i)
normals[i].normalize();
}
void Geometry::appendSmooth(const QVector3D &a, const QVector3D &n, int from)
{
// Smooth normals are acheived by averaging the normals for faces meeting
// at a point. First find the point in geometry already generated
// (working backwards, since most often the points shared are between faces
// recently added).
int v = vertices.count() - 1;
for ( ; v >= from; --v)
if (qFuzzyCompare(vertices[v], a))
break;
if (v < from)
{
// The vert was not found so add it as a new one, and initialize
// its corresponding normal
v = vertices.count();
vertices.append(a);
normals.append(n);
}
else
{
// Vert found, accumulate normals into corresponding normal slot.
// Must call finalize once finished accumulating normals
normals[v] += n;
}
// In both cases (found or not) reference the vert via its index
faces.append(v);
}
void Geometry::appendFaceted(const QVector3D &a, const QVector3D &n)
{
// Faceted normals are achieved by duplicating the vert for every
// normal, so that faces meeting at a vert get a sharp edge.
int v = vertices.count();
vertices.append(a);
normals.append(n);
faces.append(v);
}
Patch::Patch(Geometry *g)
: start(g->faces.count())
, count(0)
, initv(g->vertices.count())
, sm(Patch::Smooth)
, geom(g)
{
qSetColor(faceColor, QColor(Qt::darkGray));
}
void Patch::rotate(qreal deg, QVector3D axis)
{
mat.rotate(deg, axis);
}
void Patch::translate(const QVector3D &t)
{
mat.translate(t);
}
static inline void qMultMatrix(const QMatrix4x4 &mat)
{
if (sizeof(qreal) == sizeof(GLfloat))
glMultMatrixf((GLfloat*)mat.constData());
#ifndef QT_OPENGL_ES
else if (sizeof(qreal) == sizeof(GLdouble))
glMultMatrixd((GLdouble*)mat.constData());
#endif
else
{
GLfloat fmat[16];
GLfloat const *r = mat.constData();
for (int i = 0; i < 16; ++i)
fmat[i] = r[i];
glMultMatrixf(fmat);
}
}
//! [2]
void Patch::draw() const
{
glPushMatrix();
qMultMatrix(mat);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor);
const GLushort *indices = geom->faces.constData();
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indices + start);
glPopMatrix();
}
//! [2]
void Patch::addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n)
{
QVector3D norm = n.isNull() ? QVector3D::normal(a, b, c) : n;
if (sm == Smooth)
{
geom->appendSmooth(a, norm, initv);
geom->appendSmooth(b, norm, initv);
geom->appendSmooth(c, norm, initv);
}
else
{
geom->appendFaceted(a, norm);
geom->appendFaceted(b, norm);
geom->appendFaceted(c, norm);
}
count += 3;
}
void Patch::addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d)
{
QVector3D norm = QVector3D::normal(a, b, c);
if (sm == Smooth)
{
addTri(a, b, c, norm);
addTri(a, c, d, norm);
}
else
{
// If faceted share the two common verts
addTri(a, b, c, norm);
int k = geom->vertices.count();
geom->appendSmooth(a, norm, k);
geom->appendSmooth(c, norm, k);
geom->appendFaceted(d, norm);
count += 3;
}
}
static inline QVector<QVector3D> extrude(const QVector<QVector3D> &verts, qreal depth)
{
QVector<QVector3D> extr = verts;
for (int v = 0; v < extr.count(); ++v)
extr[v].setZ(extr[v].z() - depth);
return extr;
}
class Rectoid
{
public:
void translate(const QVector3D &t)
{
for (int i = 0; i < parts.count(); ++i)
parts[i]->translate(t);
}
void rotate(qreal deg, QVector3D axis)
{
for (int i = 0; i < parts.count(); ++i)
parts[i]->rotate(deg, axis);
}
// No special Rectoid destructor - the parts are fetched out of this member
// variable, and destroyed by the new owner
QList<Patch*> parts;
};
class RectPrism : public Rectoid
{
public:
RectPrism(Geometry *g, qreal width, qreal height, qreal depth);
};
RectPrism::RectPrism(Geometry *g, qreal width, qreal height, qreal depth)
{
enum { bl, br, tr, tl };
Patch *fb = new Patch(g);
fb->setSmoothing(Patch::Faceted);
// front face
QVector<QVector3D> r(4);
r[br].setX(width);
r[tr].setX(width);
r[tr].setY(height);
r[tl].setY(height);
QVector3D adjToCenter(-width / 2.0, -height / 2.0, depth / 2.0);
for (int i = 0; i < 4; ++i)
r[i] += adjToCenter;
fb->addQuad(r[bl], r[br], r[tr], r[tl]);
// back face
QVector<QVector3D> s = extrude(r, depth);
fb->addQuad(s[tl], s[tr], s[br], s[bl]);
// side faces
Patch *sides = new Patch(g);
sides->setSmoothing(Patch::Faceted);
sides->addQuad(s[bl], s[br], r[br], r[bl]);
sides->addQuad(s[br], s[tr], r[tr], r[br]);
sides->addQuad(s[tr], s[tl], r[tl], r[tr]);
sides->addQuad(s[tl], s[bl], r[bl], r[tl]);
parts << fb << sides;
}
class RectTorus : public Rectoid
{
public:
RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int numSectors);
};
RectTorus::RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int k)
{
QVector<QVector3D> inside;
QVector<QVector3D> outside;
for (int i = 0; i < k; ++i) {
qreal angle = (i * 2 * M_PI) / k;
inside << QVector3D(iRad * qSin(angle), iRad * qCos(angle), depth / 2.0);
outside << QVector3D(oRad * qSin(angle), oRad * qCos(angle), depth / 2.0);
}
inside << QVector3D(0.0, iRad, 0.0);
outside << QVector3D(0.0, oRad, 0.0);
QVector<QVector3D> in_back = extrude(inside, depth);
QVector<QVector3D> out_back = extrude(outside, depth);
// Create front, back and sides as separate patches so that smooth normals
// are generated for the curving sides, but a faceted edge is created between
// sides and front/back
Patch *front = new Patch(g);
for (int i = 0; i < k; ++i)
front->addQuad(outside[i], inside[i],
inside[(i + 1) % k], outside[(i + 1) % k]);
Patch *back = new Patch(g);
for (int i = 0; i < k; ++i)
back->addQuad(in_back[i], out_back[i],
out_back[(i + 1) % k], in_back[(i + 1) % k]);
Patch *is = new Patch(g);
for (int i = 0; i < k; ++i)
is->addQuad(in_back[i], in_back[(i + 1) % k],
inside[(i + 1) % k], inside[i]);
Patch *os = new Patch(g);
for (int i = 0; i < k; ++i)
os->addQuad(out_back[(i + 1) % k], out_back[i],
outside[i], outside[(i + 1) % k]);
parts << front << back << is << os;
}
QtLogo::QtLogo(QObject *parent, int divisions, qreal scale)
: QObject(parent)
, geom(new Geometry())
{
buildGeometry(divisions, scale);
}
QtLogo::~QtLogo()
{
qDeleteAll(parts);
delete geom;
}
void QtLogo::setColor(QColor c)
{
for (int i = 0; i < parts.count(); ++i)
qSetColor(parts[i]->faceColor, c);
}
//! [3]
void QtLogo::buildGeometry(int divisions, qreal scale)
{
qreal cw = cross_width * scale;
qreal bt = bar_thickness * scale;
qreal ld = logo_depth * scale;
qreal th = tee_height *scale;
RectPrism cross(geom, cw, bt, ld);
RectPrism stem(geom, bt, th, ld);
QVector3D z(0.0, 0.0, 1.0);
cross.rotate(45.0, z);
stem.rotate(45.0, z);
qreal stem_downshift = (th + bt) / 2.0;
stem.translate(QVector3D(0.0, -stem_downshift, 0.0));
RectTorus body(geom, 0.20, 0.30, 0.1, divisions);
parts << stem.parts << cross.parts << body.parts;
geom->finalize();
}
//! [3]
//! [4]
void QtLogo::draw() const
{
geom->loadArrays();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
for (int i = 0; i < parts.count(); ++i)
parts[i]->draw();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
//! [4]
window.cpp
// window.cpp
#include <QtWidgets>
#include "window.h"
#include "ui_window.h"
#include "glwidget.h"
#include <QSlider>
Window::Window(QWidget *parent) :
QWidget(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
//glWidget = new GLWidget;
glWidget = ui->widget;
xSlider = createSlider();
ySlider = createSlider();
zSlider = createSlider();
connect(xSlider, SIGNAL(valueChanged(int)), glWidget, SLOT(setXRotation(int)));
connect(glWidget, SIGNAL(xRotationChanged(int)), xSlider, SLOT(setValue(int)));
connect(ySlider, SIGNAL(valueChanged(int)), glWidget, SLOT(setYRotation(int)));
connect(glWidget, SIGNAL(yRotationChanged(int)), ySlider, SLOT(setValue(int)));
connect(zSlider, SIGNAL(valueChanged(int)), glWidget, SLOT(setZRotation(int)));
connect(glWidget, SIGNAL(zRotationChanged(int)), zSlider, SLOT(setValue(int)));
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(glWidget);
mainLayout->addWidget(xSlider);
mainLayout->addWidget(ySlider);
mainLayout->addWidget(zSlider);
setLayout(mainLayout);
xSlider->setValue(15 * 16);
ySlider->setValue(345 * 16);
zSlider->setValue(0 * 16);
setWindowTitle(tr("Hello GL"));
}
QSlider *Window::createSlider()
{
QSlider *slider = new QSlider(Qt::Vertical);
slider->setRange(0, 360 * 16);
slider->setSingleStep(16);
slider->setPageStep(15 * 16);
slider->setTickInterval(15 * 16);
slider->setTickPosition(QSlider::TicksRight);
return slider;
}
Window::~Window()
{
delete ui;
}
void Window::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Escape)
close();
else
QWidget::keyPressEvent(e);
}
:-) I have nailed it!
The problem was: The Q Logo does not appear in QT5. Although it does work in QT4.
After spending weeks on this problem, googling for hours, going through the hassle of compiling QT many many times, I have finally solved the problem with this code and the mystery of opengl_es and ANGLE
So for those of us completely baffled as to why QT OpenGL examples code prior to QT5 may not work or work properly, it could be the same issue as this code.
Basically comment out or omit references to QT_OPENGL_ES.
In this hello world Q example:
Comment this out as shown contained in the Qlogo.cpp file
/*
#ifndef QT_OPENGL_ES
else if (sizeof(qreal) == sizeof(GLdouble))
glMultMatrixd((GLdouble*)mat.constData());
#endif
*/
Lots of code lovin' to you all.

Resources