How to put QGraphicsEffect on QScrollBar inside QScrollArea? - c++

I try to set QGraphicsDropShadowEffect on a QScrollBar. This code works:
QGraphicsDropShadowEffect * dse = new QGraphicsDropShadowEffect();
dse->setBlurRadius(10);
dse->setColor(Qt::red);
dse->setOffset(0);
ui->verticalScrollBar->setGraphicsEffect(dse); // verticalScrollBar is `QScrollBar`.
However the following does not:
QGraphicsDropShadowEffect * dse = new QGraphicsDropShadowEffect();
dse->setBlurRadius(10);
dse->setColor(Qt::red);
dse->setOffset(0);
ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
ui->scrollArea->verticalScrollBar()->setGraphicsEffect(dse);
In the second example code I try to set effect on a slider inside QScrollArea but it does not apply to it. However, it can be applied to the whole scrollArea by ui->scrollArea->setGraphicsEffect(dse). What am I doing wrong?

The problem I had was caused by parent widget of QScrollBar. So, QScrollArea has item area and scroll bar area. Scroll bar area contains QWidgets and QScrollBars actually placed on these QWidgets. So, to make this work I actually had to set effect for the parent widget:
for(auto *child : ui->scrollArea->findChildren<QScrollBar*>()) {
if (child->orientation() == Qt::Vertical) {
auto * dse = new QGraphicsDropShadowEffect();
dse->setBlurRadius(10);
dse->setColor(Qt::red);
dse->setXOffset(-3);
dse->setYOffset(0);
child->parentWidget()->setGraphicsEffect(dse);
qDebug() << child->metaObject()->className(); // QScrollBar
qDebug() << child->parentWidget()->metaObject()->className(); // QWidget
}
}

Related

How do I prevent QListView in QGraphicsScene from drawing outside scroll area when scaling with QT_SCALE_FACTOR

When I display a QListWidget or QListView in a QGraphicsScene the text for each item is drawn outside of the widget boundaries if scroll bars are necessary. This only occurs when I use QT_SCALE_FACTOR to scale the application. Is there a way to prevent the list widget/list view items from being displayed outside the scroll area without explicitly setting a width for the items? If I set the width I lose some of the text. I have also tried setting the GraphicsItemFlag QGraphicsItem::ItemClipsToShape. This keeps the overhang restricted to the width of the outer widget but I want to prevent overhang entirely.
QListWidget in QGraphicsScene
QWidget *w = new QWidget();
QVBoxLayout *l = new QVBoxLayout(w);
lw = new QListWidget();
l->addWidget(lw);
QGraphicsProxyWidget *pw = scene()->addWidget(w);
pw->resize(200,300);
for(int i = 0; i < 25; i++) {
QListWidgetItem *litem = new QListWidgetItem("Text text text text text text text");
lw->insertItem(0, litem);
}
Setting the cache mode to QGraphicsItem::DeviceCoordinateCache prevents the listview/listwidget text from displaying outside the boundaries of the widget. The text does become a little blurry but the user can still read it. Thank you harism for your response!
pw->setCacheMode(QGraphicsItem::DeviceCoordinateCache);

How to adjust QTextEdit to fit it's contents

I'm developing a Qt Application and I'm trying to find a way to use QTextEdit as a label with long text without the scroll bar. In my ui I have a QScrollArea and inside of it I want to place a couple off QTextEdit widgets and I only want use scrolling inside QScrollArea. Problem is that no matter how I try to resize the QTextEdit it seems it has a maximum height and cuts of text, even if I set the size manually and QTextEdit::size returns the correct value.
I did the same thing with QLabel and it works fine, but in this case I need some methods that are only provided in QTextEdit.
I found this post:
Resizing QT's QTextEdit to Match Text Height: maximumViewportSize()
And the answer given was the following:
I have solved this issue. There were 2 things that I had to do to get
it to work:
Walk up the widget hierarchy and make sure all the size policies made
sense to ensure that if any child widget wanted to be big/small, then
the parent widget would want to be the same thing.
This is the main
source of the fix. It turns out that since the QTextEdit is inside a
QFrame that is the main widget in a QScrollArea, the QScrollArea has a
constraint that it will not resize the internal widget unless the
"widgetResizable" property is true. The documentation for that is
here: http://doc.qt.io/qt-4.8/qscrollarea.html#widgetResizable-prop.
The documentation was not clear to me until I played around with this
setting and got it to work. From the docs, it seems that this property
only deals with times where the main scroll area wants to resize a
widget (i.e. from parent to child). It actually means that if the main
widget in the scroll area wants to ever resize (i.e. child to parent),
then this setting has to be set to true. So, the moral of the story is
that the QTextEdit code was correct in overriding sizeHint, but the
QScrollArea was ignoring the value returned from the main frame's
sizeHint.
The problem is that I have no idea how to access the QTextEdit's QScrollArea to enable widgetResizable. Can anyone explain how I can achieve this or suggest a different way of resizing QTextEdit to perfectly fit it's content?
This will allow the height of the text box to change as required. You can edit the code a little to handle the width as well.
connect( m_textField, SIGNAL( textChanged() ), this, SLOT( onTextChanged() ) );
void MyClass::onTextChanged()
{
QSize size = m_textField->document()->size().toSize();
m_textField->setFixedHeight( size.height() + 3 );
}
Try this one :
QTextEdit textEdit;
textEdit.setHtml("<p>test test test test test test</p><p>|||||||||</p>");
textEdit.show();
textEdit.setFixedWidth(textEdit.document()->idealWidth() +
textEdit.contentsMargins().left() +
textEdit.contentsMargins().right());
Without a concrete example it's difficult to judge, but... it sounds as if you simply want a QTextEdit whose sizeHint depends on the current document size.
class text_edit: public QTextEdit {
using super = QTextEdit;
public:
explicit text_edit (QWidget *parent = nullptr)
: super(parent)
{
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
virtual QSize sizeHint () const override
{
QSize s(document()->size().toSize());
/*
* Make sure width and height have `usable' values.
*/
s.rwidth() = std::max(100, s.width());
s.rheight() = std::max(100, s.height());
return(s);
}
protected:
virtual void resizeEvent (QResizeEvent *event) override
{
/*
* If the widget has been resized then the size hint will
* also have changed. Call updateGeometry to make sure
* any layouts are notified of the change.
*/
updateGeometry();
super::resizeEvent(event);
}
};
Then use as...
QScrollArea sa;
sa.setWidgetResizable(true);
text_edit te;
te.setPlainText(...);
sa.setWidget(&te);
sa.show();
It appears to work as expected in the few tests I've done.
In ui i defined QTextEdit *textEdit object. I write it as height scalable-content :
int count = 0;
QString str = "";
// set textEdit text
ui->textEdit->setText("hfdsf\ncsad\nfsc\dajkjkjkjhhkdkca\n925");
str = ui->textEdit->toPlainText();
for(int i = 0;i < str.length();i++)
if(str.at(i).cell() == '\n')
count++;
// resize textEdit (width and height)
ui->textEdit->resize(ui->textEdit->fontMetrics().width("this is the max-length line in qlabel")
, ui->textEdit->fontMetrics().height() * (count + 2));
Notice : this work if you change QTextEdit font face or size! just in height scalable (before every thing set your QTextEdit frameShape to BOX).
if you want do width scalable-content, you should do these steps :
read QTextEdit(textEdit object) text as line to line
calculate every line length
select maximum of line length
use of QTextEdit::fontMetrics().width(QString str) for investigate str size in width
I hope this can help you...

How can I stretch a QLayout or QFrame, nested within a bigger layout?

I currently have this code set up to create a sidebar and I'm not entirely sure how to stretch it so that the left, top, and bottom sides touch the edge of the window.
QFrame *sidebar = new QFrame;
QLabel *sideItemA = new QLabel("Item A");
QLabel *sideItemB = new QLabel("Item B");
QVBoxLayout *sidebarLayout = new QVBoxLayout;
sidebarLayout->addWidget(sideItemA);
sidebarLayout->addWidget(sideItemB);
sidebarLayout->addStretch();
sidebar->setLayout(sidebarLayout);
sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
sidebar->setStyleSheet("background-color:#FFFFFF");
sidebar->setMinimumWidth(150);
mainLayout->addWidget(sidebar);
Here is a screenshot of what the above code looks like:
I've tried doing this using nested layouts too and I get the same result. Any pointers? Is this even the best way to do it?

QtChart - C++ - Saving a chart which wasn't displayed

I'm trying to save a chart to a file, in a QTextDocument in this example :
QTextDocument doc("Frame rate test\n");
QTextCursor cursor(&doc);
cursor.movePosition(QTextCursor::End);
if (getTestFinishedStatus())
{
QPixmap pix = _pFrameRateChart->grab(); //_pFrameRateChart is QChartView
cursor.insertImage(pix.toImage());
}
QTextDocumentWriter docWriter;
docWriter.setFileName("framerate.odf");
docWriter.setFormat("ODF");
docWriter.write(&doc);
The problem is the result isn't same if I'm displaying the chart in an ui.
Here is the result when not displayed :
Here is the result when displayed :
Obviously I would like to have the second result even when I don't add the ChartView to a widget to display it on an ui.
I've tried resizing the QChartView, resizing the QChart, adding the Chart to a temporarly widget and QVBoxLayout then saving it, showing temporarly the QChartView before saving it etc... but didn't managed to get a good result.
I use the following code to render a QGraphivsView on a Pixmap, since QtCharts is based on QGraphivsView, I think this will also work.
Try to render the image instead of trying to grab the pixmap.
void Printer::putProfileImage(QRect profilePlaceholder, QRect viewPort, QPainter *painter, QGraphivsView* profile)
{
int x = profilePlaceholder.x() - viewPort.x();
int y = profilePlaceholder.y() - viewPort.y();
QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height());
profile->render(painter, pos);
}
I didn't find any easy way to this, so here's my solution, which is more like a workaround though :
QPixmap ChartView::getChartPixmap()
{
QWidget* w = new QWidget; //creating a temporary widget, which will enable to display the chart
w->resize(REPORT_IMAGE_WIDTH, REPORT_IMAGE_HEIGHT);
QVBoxLayout *vl;
vl = new QVBoxLayout(w);
vl->addWidget(this); //'this' being the QChartView
w->show(); //showing the widget so it is resized and can be grabbed with the correct dimensions
QTest::qWait(500); //we need to wait for a little for the graph to be drawn otherwise you'll still have the same size problem
QPixmap pixmap = w->grab(); //retrieve the pixmap
w->hide(); //hiding the widget
return pixmap;
}
It's working but you'll have a small window opened with the graph for 500 ms.

Qt QHBoxLayout issue?

I use an extended QGroupBox as the widget for QDockWidget in my QMainWindow.
Here is the code snippet:
RzPlaneViewerControlPanelWidget::RzPlaneViewerControlPanelWidget(QWidget *parent) : QGroupBox(parent) {
// TODO Auto-generated constructor stub
init();
}
void RzPlaneViewerControlPanelWidget::init()
{
QHBoxLayout *hbox=new QHBoxLayout;
hbox->setSizeConstraint(hbox->SetMinimumSize);
hbox->setSpacing(0);
hbox->setStretch(1,0);
setMaximumHeight(50);
QScrollBar *scrollbar=new QScrollBar;
scrollbar->setOrientation(Qt::Horizontal);
scrollbar->setMouseTracking(true);
scrollbar->setFocusPolicy(Qt::StrongFocus);
scrollbar->setMinimum(0);
scrollbar->setSingleStep(1);
QLineEdit *qlineedit = new QLineEdit;
qlineedit->setMaximumWidth(60);
qlineedit->setReadOnly(true);
hbox->addWidget(scrollbar);
hbox->addWidget(qlineedit);
//hbox->addWidget(new )
setLayout(hbox);
}
Here is how I add this widget to QDockWidget :
RzPlaneViewerControlPanelWidget *controlPanel=new RzPlaneViewerControlPanelWidget ;
controlPanel->init();
QDockWidget controlPanelDockWidet=new QDockWidget;
controlPanelDockWidet->setAllowedAreas(Qt::BottomDockWidgetArea);
controlPanelDockWidet->setFeatures(QDockWidget::DockWidgetVerticalTitleBar);
controlPanelDockWidet->setWidget(controlPanel);
But the ScrollBar is not stretched as I expected -
Here's how it looks like -
This is what I want -
From a quick read, I'd try doing:
hbox->addWidget(scrollbar, 1);
The second (optional) argument to addWidget is the stretch factor. From the Qt docs:
If the stretch factor is 0 and nothing else in the QBoxLayout has a stretch factor greater than zero, the space is distributed according to the QWidget:sizePolicy() of each widget that's involved.
Also, note that your:
hbox->setStretch(1,0);
call does not have any effect, as it is setting the qlineedit's stretch factor to 0, but that's already the default.