I am using the following tab style for drawing tabbar text horizontally for
east tab position. The text is drawn ok, as long as i dont set any margin for
QTabBar::tab. In that case the text orientation remains vertical with strange offset.
class TabStyle : public QProxyStyle {
public:
explicit TabStyle(Qt::Orientation orientation, QStyle *baseStyle = 0)
: QProxyStyle(baseStyle), mOrientation(orientation) {}
void drawControl(ControlElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const {
if (element == CE_TabBarTabLabel) {
if (const QStyleOptionTab *tab =
qstyleoption_cast<const QStyleOptionTab *>(option)) {
QStyleOptionTab opt(*tab);
opt.shape = QTabBar::RoundedNorth;
return QProxyStyle::drawControl(element, &opt, painter, widget);
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
private:
const Qt::Orientation mOrientation;
};
class TabWidget : public QTabWidget {
public:
explicit TabWidget(QWidget *parent = 0,
Qt::Orientation orientation = Qt::Horizontal)
: QTabWidget(parent) {
QTabBar *tabBar = new QTabBar;
tabBar->setStyle(new TabStyle(orientation));
setTabBar(tabBar);
}
};
Why don't you Qt style sheets ? In the designer you could check it on the fly and you don't need write any code for that.
Related
I have a QGraphicsScene which contains some symbols (many symbols are repeated) . These symbols consist of line. I have created a separate class for line which inherits from QGraphicsLineItem. All these lines are grouped under one entity using QGraphicsItemGroup.
Here is code structure:
I have a map which contains all the line co-ordinates. I am taking co-ordinates from map and giving those to Qt's API.
myGroup.h
class myGroup: public QGraphicsItemGroup
{
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void PaintSymbol(QGraphicsItem *item, QPainter *painter, const
QStyleOptionGraphicsItem *option);
}
myGroup.cpp
void myGroup::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
auto copied_option = *option;
copied_option.state &= ~QStyle::State_Selected;
auto selected = option->state & QStyle::State_Selected;
myGroup::paint(painter, &copied_option, widget);
if (selected)
{
foreach (QGraphicsItem* item, _scene->selectedItems()) {
myGroup* inst = qgraphicsitem_cast<myGroup*>(item);
if (!inst)
continue;
QList<QGraphicsItem*> childItems = inst->childItems();
foreach (QGraphicsItem* chItem, childItems) {
if (myLine* line = dynamic_cast<myLine*>(chItem)) {
PaintSymbol(line, painter, option);
}
void myGroup::PaintSymbol(QGraphicsItem* item, QPainter* painter, const
QStyleOptionGraphicsItem* option)
{
painter->save();
painter->setPen(QPen(option->palette.windowText(), 0, Qt::SolidLine));
if(myLine* line = dynamic_cast<myLine*>(item))
painter->drawPath(line->shape());
painter->restore();
}
myLine.h
class myLine: public QGraphicsLineItem {
public:
myLine();
myLine(int x1, int y1, int x2, int y2, QGraphicsItem *parent = nullptr);
};
DrawFun().cpp
myGroup* GroupItem= new myGroup();
for( iterating over map )
{
// taking co-ordinates
myLine* line = new myLine(first, second, third, fourth);
GroupItem->addToGroup(line);
}
// Control comes here when I click on symbol on screen.
HighlightObject()
{
// here I find symbols under click. ( i.e. itemUnderClick )
myGroup* gItem = qgraphicsitem_cast<myGroup*>(itemUnderClick);
if (gItem)
gItem->setSelected(true); // from here control goes to paint() in myGroup
}
Now issue is :
For some symbols, selected variable in paint() gives value as ( in debugging I found)
QStyle::State_None (0x0000)
And for some symbols it gives value as :
QStyle::State_Selected (0x8000)
For value : QStyle::State_None (0x0000) paint() does not highlight object.
Where am I wrong in heighlighting all objects ?
I am subclassing QHeaderView to add a filtering icon in the horizontal header of a QTableView. The QTableView has sorting capability activated consume a QSortFilterProxyModel, until now it works fine.
However when I try to subclass QHeaderView and use it as column header, only the first column shows the filter icon.
headerview_filter.h
#ifndef HEADERVIEW_FILTER_H
#define HEADERVIEW_FILTER_H
#include <QHeaderView>
class HeaderView_Filter : public QHeaderView
{
Q_OBJECT
public:
explicit HeaderView_Filter(Qt::Orientation orientation, QWidget * parent = nullptr);
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override;
private:
const QPolygonF _funel = QPolygonF({{22.0,36.0},{22.0,22.0},{10.0,10.0},{40.0,10.0},{28.0,22.0},{28.0,36.0}});
};
#endif // HEADERVIEW_FILTER_H
headerview_filter.cpp
#include "headerview_filter.h"
HeaderView_Filter::HeaderView_Filter(Qt::Orientation orientation, QWidget * parent)
: QHeaderView(orientation, parent)
{
setSectionsClickable(true);
}
void HeaderView_Filter::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->restore();
const double scale = 0.6*rect.height()/50.0;
painter->setBrush(Qt::black);
painter->translate(0,5);
painter->scale(scale, scale);
painter->drawPolygon(_funel);
painter->restore();
}
using it in form :
auto* tableView = _ui->tableView_Data;
tableView->setModel(_sortFilterProxyModel);
tableView->setSortingEnabled(true);
tableView->setHorizontalHeader(new HeaderView_Filter(Qt::Horizontal,tableView));
I found the solution while typing it and prefered to post the code for other to use.
The position of the drawing must be translated relative to the drawing rectangle provided as argument of paintSection :
void HeaderView_Filter::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->restore();
const double scale = 0.6*rect.height()/50.0;
painter->setBrush(Qt::black);
// Here
painter->translate(rect.x(),rect.y()+5);
//
painter->scale(scale, scale);
painter->drawPolygon(_funel);
painter->restore();
}
I am new at Qt and I want to write my custom QGraphicsItem which contains a rectangle and couple of buttons. I want to write a single custom component that could be easily added to QGraphicsScene and moved or resized with contents(buttons and rectangles) in it. In the end I want to add multiple customized QGraphicsItem to my QGraphicsScene. My question is how can I write this customized QGraphicsItem that contains buttons and rectangles which relative positions to each other are constant.
In this drawing green colored rectangles represent buttons and their relative position to each other always stays same (as if they are placed using qlayouts)
Thanks to #replete, from the example at http://doc.qt.io/qt-5/qtwidgets-graphicsview-dragdroprobot-example.html I was able to create a custom QGraphicsItem with clickable sub-parts in it. In code below BboxItem represents container QGraphicsItem and BboxItemContent represents childs of it. By emitting signals whith mause click events I was able to implement button like features. And I can move the BboxItem by setting its bounding rectangle.
BboxItem related source code:
BboxItemContent::BboxItemContent(QGraphicsItem *parent, int type, QColor color,QRectF *rect)
: QGraphicsObject(parent)
{
content_rectangle = rect;
content_type = type;
switch (type)
{
case 0:
rectangle_color = color;
icon = 0;
break;
case 1:
icon = new QImage(":/resource/assets/info_btn.png");
break;
case 2:
icon = new QImage(":/resource/assets/close_btn.png");
break;
}
}
BboxItemContent::~BboxItemContent()
{
delete icon;
}
QRectF BboxItemContent::boundingRect() const
{
return QRectF(content_rectangle->x(), content_rectangle->y(), content_rectangle->width(), content_rectangle->height());
}
void BboxItemContent::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget)
{
if (icon == 0)
{
QPen pen(rectangle_color, 3);
painter->setPen(pen);
painter->drawRect(*content_rectangle);
}
else
{
painter->drawImage(*content_rectangle, *icon);
}
}
void BboxItemContent::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
emit bboxContentClickedSignal();
}
void BboxItemContent::setRect(QRectF *rect)
{
content_rectangle = rect;
update();
}
BboxItem::BboxItem(QGraphicsItem *parent,QRectF *itemRect) : BboxItemContent(parent,0,Qt::red, itemRect)
{
setFlag(ItemHasNoContents);
bbox_area = new BboxItemContent(this, 0, Qt::red, itemRect);
info_btn = new BboxItemContent(this, 1, Qt::red, new QRectF(itemRect->x() - 30, itemRect->y(), 30, 30));
connect(info_btn, &BboxItemContent::bboxContentClickedSignal, this, &BboxItem::onInfoClickedSlot);
delete_btn= new BboxItemContent(this, 2, Qt::red, new QRectF((itemRect->x()+itemRect->width()), itemRect->y(), 30, 30));
connect(delete_btn, &BboxItemContent::bboxContentClickedSignal, this, &BboxItem::onDeleteClickedSlot);
}
void BboxItem::onDeleteClickedSlot()
{
//delete clicked actions
}
void BboxItem::onInfoClickedSlot()
{
//info clicked actions
}
void BboxItem::setRect(QRectF *rect)
{
bbox_area->setRect(rect);
info_btn->setRect(new QRectF(rect->x() - 30, rect->y(), 30, 30));
delete_btn->setRect(new QRectF((rect->x() + rect->width()), rect->y(), 30, 30));
}
Related Headers:
class BboxItemContent : public QGraphicsObject
{
Q_OBJECT
public:
BboxItemContent(QGraphicsItem *parent = 0, int type = 0, QColor color = Qt::red, QRectF *rect=nullptr);
~BboxItemContent();
// Inherited from QGraphicsItem
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
void setRect(QRectF *rect);
signals:
void bboxContentClickedSignal();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
private:
QImage *icon;
QColor rectangle_color;
QRectF *content_rectangle;
int content_type;
};
class BboxItem : public BboxItemContent {
Q_OBJECT
public:
BboxItem(QGraphicsItem *parent = 0,QRectF *itemRect=nullptr);
void setRect(QRectF *rect);
private slots:
void onDeleteClickedSlot();
void onInfoClickedSlot();
private:
BboxItemContent *delete_btn;
BboxItemContent *bbox_area;
BboxItemContent *info_btn;
};
I'd like to create a vertical button in Qt (using C++, not Python), with text rotated 90ยบ either clockwise or counterclockwise. It doesn't seem to be possible with a standard QPushButton.
How could I do it?
In order to create a vertical button in Qt, you can subclass QPushButton so that the dimensions reported by the widget are transposed, and also modify the drawing event to paint the button with the proper alignment.
Here's a class called OrientablePushButton that can be used as a drop-in replacement of the traditional QPushButton but also supports vertical orientation through the usage of setOrientation.
Aspect:
Sample usage:
auto anotherButton = new OrientablePushButton("Hello world world world world", this);
anotherButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
anotherButton->setOrientation(OrientablePushButton::VerticalTopToBottom);
Header file:
class OrientablePushButton : public QPushButton
{
Q_OBJECT
public:
enum Orientation {
Horizontal,
VerticalTopToBottom,
VerticalBottomToTop
};
OrientablePushButton(QWidget * parent = nullptr);
OrientablePushButton(const QString & text, QWidget *parent = nullptr);
OrientablePushButton(const QIcon & icon, const QString & text, QWidget *parent = nullptr);
QSize sizeHint() const;
OrientablePushButton::Orientation orientation() const;
void setOrientation(const OrientablePushButton::Orientation &orientation);
protected:
void paintEvent(QPaintEvent *event);
private:
Orientation mOrientation = Horizontal;
};
Source file:
#include <QPainter>
#include <QStyleOptionButton>
#include <QDebug>
#include <QStylePainter>
OrientablePushButton::OrientablePushButton(QWidget *parent)
: QPushButton(parent)
{ }
OrientablePushButton::OrientablePushButton(const QString &text, QWidget *parent)
: QPushButton(text, parent)
{ }
OrientablePushButton::OrientablePushButton(const QIcon &icon, const QString &text, QWidget *parent)
: QPushButton(icon, text, parent)
{ }
QSize OrientablePushButton::sizeHint() const
{
QSize sh = QPushButton::sizeHint();
if (mOrientation != OrientablePushButton::Horizontal)
{
sh.transpose();
}
return sh;
}
void OrientablePushButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QStylePainter painter(this);
QStyleOptionButton option;
initStyleOption(&option);
if (mOrientation == OrientablePushButton::VerticalTopToBottom)
{
painter.rotate(90);
painter.translate(0, -1 * width());
option.rect = option.rect.transposed();
}
else if (mOrientation == OrientablePushButton::VerticalBottomToTop)
{
painter.rotate(-90);
painter.translate(-1 * height(), 0);
option.rect = option.rect.transposed();
}
painter.drawControl(QStyle::CE_PushButton, option);
}
OrientablePushButton::Orientation OrientablePushButton::orientation() const
{
return mOrientation;
}
void OrientablePushButton::setOrientation(const OrientablePushButton::Orientation &orientation)
{
mOrientation = orientation;
}
How do I add color on the sides of a tableView?
You should subclass QHeaderView and implement your own class like:
#include<QtWidgets>
class HeaderView: public QHeaderView
{
public:
HeaderView():QHeaderView(Qt::Vertical)
{}
void paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const
{
QBrush brush;
if(logicalIndex == 0)
brush.setColor(QColor(Qt::red));
else
brush.setColor(QColor(Qt::blue));
painter->fillRect(rect, brush);
QPen pen(Qt::white);
painter->setPen(pen);
painter->drawText(rect,QString("Row %1").arg(logicalIndex));
}
};
Next set an instance of HeaderView as the vertical header of the QTableView:
HeaderView vView;
tableview.setVerticalHeader(&vView);