How to add an effect on QGraphicsView? - c++

I'm trying to add a blur effect on my graphicsView but i have to trigger the action twice to apply the effect.The first time i trigger it, it applies the effect on the graphicsView's borderline and on the second trigger it applies it on the scene.Here is my code(the same with colorize effect):
void MainWindow::on_actionBlur_triggered()
{
QGraphicsBlurEffect *a=new QGraphicsBlurEffect;
a->setBlurHints(QGraphicsBlurEffect::QualityHint);
a->boundingRectFor(ui->graphicsView->viewport()->rect());
ui->graphicsView->setGraphicsEffect(a);
}
Can you spot the mistake or propose a different way fo doing this?

I've find a solution by calling the trigger for a second recursively.In numOfTriggers i save the times that i called it.
void Editor::on_actionBlur_triggered()
{
if(numOfTriggers<2){
QGraphicsBlurEffect *a=new QGraphicsBlurEffect;
a->setBlurHints(QGraphicsBlurEffect::QualityHint);
a->boundingRectFor(ui->graphicsView->viewport()->rect());
ui->graphicsView->setGraphicsEffect(a);
numOfTriggers++;
on_actionBlur_triggered();
}
else{
numOfTriggers=0;
}
}

I have another idea : you should pass the QGraphicsView to your QGraphicsBlurEffect in constructor.
QGraphicsBlurEffect* a = new QGraphicsBlurEffect(ui->graphicsView);
Give a try with your mainWindow or "this" if not working.

Related

qt5 QGraphicsScene setBackgroundBrush() not always work when called frequently

I want to write an tool of objective annotation using qt5 MinGw32, which could annotate object in video file and diplay them during playing. So QGraphicsScene is inherited to implementation the function.
Something wrong happens when I change the QGraphicsScene's background frequently(e.g. 30 fps): most of time it works as expected while sometimes the background could not move.
Here is my code:
void MyGraphicsScene::UpdateFrame(QImage image)
{
QPixmap pixmap = QPixmap::fromImage(image);
//fix the view's size and scene's size
views().first()->setFixedSize(pixmap.size());
setSceneRect(0,0, pixmap.width(), pixmap.height());
setBackgroundBrush(QBrush(pixmap));
}
...
//In another thread
void Thread::run()
{
...
myScene.UpdateFrame(newImage);
...
}
I have search through the qt's document and found no answer.
However, there is something strange:
when wrong thing happens, I find the background continues to change, but it didn't show change on the screen unless I move the app to another screen (I have two screen). However, with the app moved, the QGraphicsScene's background just change once and becomes static afterwards.
I guess the background has been changed but doesn't repainted, so I used update(), but it didn't help.
BTW, I couldn't reproduce the occasion, sometiems it happens, somtimes not.
do I need to represented any methods? Or I called the methods in a wrong way? Or is there an alternative approach that would work?
Many thanks for your help in advance.
You should not change QtGui elements from a different thread by calling a method directly.
Use the Qt signal-slot concept.
Calling update() is not necessary.
class MyGraphicsScene{...
....
signals:
void singalFromThread(QImage image);
public:
//CTor
MyGraphicsScene()
{
connect(this, SIGNAL(singalFromThread(QImage)),this,SLOT(UpdateFrame(QImage)));
}
//Call this method from your thread
void updateForwarder(QImage image)
{
//Jump into gui thread
emit singalFromThread(image);
}
public slots:
void UpdateFrame(QImage image)
{
setBackgroundBrush(....);
}
};

QToolbar force expand on too many QActions

Hi all is there any way to automatically expand a QToolbar if there is too many QActions in?
Using Qt version 5.4.1 C++11
Ive tried :ui->mainToolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred)
But this only expands it horizontally. I need it to expand vertically like the Expand button does.
Always expanding a toolbar vertically is not possible as far as I know (never seen it). A solution would be to add multiple toolbars. This way, you can arrange them one under the other.
What you can try is to add a custom widget to the toolbar that grows horizontally. This was proposed here by using a QScrollArea... Not sure whether this is exactly what you want, but it may work good enough.
This is how you can make a function to expand/retract a QToolbar. Firstly using a Forloop get all the child widgets from the QToolbar. You can use a Bool to lock to only get the first Widget which is the Expanding button/Action.
bool get_first_action{true};
for(QWidget* widget : ui->myToolBar->findChildren<QWidget*>())
{
if(get_first_action)
{
get_first_action = false;
// This is the expanding action!
m_action_expand = widget;
}
}
Or you can do this which is probably a bit safer.
for(QWidget* widget : ui->myToolBar->findChildren<QWidget*>())
{
if(widget->objectName() == "qt_toolbar_ext_button")
{
// This is the expanding action!
m_action_expand = widget;
}
}
Once you have the sneaky expanding action assign it to a member varible
// Make sure to initialize this in the constructor!
// m_action_expand = new QWidget(this // parent)
QWidget* m_action_expand;
Now create a handy function with a good name;
void MainWindow::forceToolbarExpand()
{
// Grab the position of the expanding action/widget
QPointF pos(m_action_expand->pos());
// Create a fake/dummy event that replicates the mouse button press
QMouseEvent event_press(QEvent::MouseButtonPress, pos, Qt::LeftButton,0, 0);
// Create a fake/dummy event that replicates the mouse button release
QMouseEvent event_release(QEvent::MouseButtonRelease, pos, Qt::LeftButton,0, 0);
// These two events together will fire the QAction::Toggled signal.
// Make sure to send the events!
QApplication::sendEvent(m_action_expand, &event_press);
QApplication::sendEvent(m_action_expand, &event_release);
}
And there we have it your QToolbar, if it can be expanded/retracted now will when you call this function. I'm not too sure if you can directly Moc/fake the toggled event but you can try it. I know this method works so yeah.

Qt application crashes after call to removeItem() in QGrahicsScene

I'm facing a problem I cannot explain yet. In the "Designer" GUI there is a QGraphicsView which I use as a placeholder for a custom GraphicsView. I have overridden the resizeEvent() method there and set the scene's rect.
The scene which is a custom class, too I'd like to use to display a graph.
The problem: Sometimes when starting the application it crashes and sometimes it doesn't. This behavior does not follow a rule, i.e. sometimes I start it ten times before crashing sometimes three times and so on.
I took a screenshot of the call stack but seems like I am not capable of understanding the problem. Hope someone of you does.
First things first, here is the code:
mainwindow.cpp
graph = new GraphScene(this);
ui->gv_graph->setScene(graph);
graph->addAxisLabels("P", "t");
graphicsview.cpp
GraphicsView::GraphicsView(QWidget *parent)
:QGraphicsView(parent)
{
}
void GraphicsView::resizeEvent(QResizeEvent *event)
{
if(GraphScene *s = dynamic_cast<GraphScene*>(scene()))
s->updateSceneRect(QRectF(QPointF(0,0), event->size()));
}
graphscene.cpp
const float GraphScene::margin = 20.0f;
GraphScene::GraphScene(QObject *parent)
:QGraphicsScene(parent)
{
}
void GraphScene::updateSceneRect(const QRectF &rect)
{
setSceneRect(rect);
if(_frameRect)
removeItem(_frameRect);
_frameRect = new QGraphicsRectItem;
_frame.setTopLeft(QPointF(margin, margin));
_frame.setWidth(rect.width()-2*margin);
_frame.setHeight(rect.height()-2*margin);
_frameRect->setRect(_frame);
addItem(_frameRect);
}
void GraphScene::addAxisLabels(const QString& xLabel, const QString& yLabel)
{
if(_xLabel)
removeItem(_xLabel);
if(_yLabel)
removeItem(_yLabel);
_xLabel = new QGraphicsSimpleTextItem(xLabel);
_xLabel->setX(margin+1);
_xLabel->setY(margin+1);
addItem(_xLabel);
//_yLabel = new QGraphicsSimpleTextItem;
}
So as what I see from the call stack the problem occurs when calling removeItem() in one of the both functions above.
The screenshot:
Environment information:
Can someone provide some help, hints or whatever. This would be very much appreciated. Thank you!

what wxYield() returns? Is it related to why my guauge is not updated?

I am using wxwidgets and I have a code like this:
gaugeProgressFolders->SetRange(folderList.size());
for(int i=0;i<folderList.size();i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
wxYield();
}
The wxYeild doesn't update guauge. I am wondering why it is not working?
Looking at wxYield, I noted that it returns a bool but there is no documentation on what it returns.
Why my guauge is not update and how I can fix it?
what wxYield returns?
You do not say what gaugeProgressFolders is. Perhaps it is wxGauge?
In any case, why do you expect wxYield to magically update the display?
You have to write code to update the display.
Assuming various things about your code, you could write something like this:
gaugeProgressFolders->SetRange(folderList.size());
for(int i=0;i<folderList.size();i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
// wxYield(); Don't call this, it does nothing
// force the window to be repainted RIGHT NOW.
Refresh();
Update();
}
You might also try the following, for the sake of efficency and less flicker
// force the gauge to be repainted.
gaugeProgressFolders->Refresh();
gaugeProgressFolders->Update();
Perhaps this is a little late to respond, but I don't think wxYield() is the right call for your purpose of updating a gauge. Perhaps try:
gaugeProgressFolders->SetRange(folderList.size());
for (int i = 0; i < folderList.size(); i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
this->Layout(); //this being your window/dialog/frame
}
Layout() forces the layout to redraw. It has been effective for me in the past.

QGraphicsView missing text on some draws

I've tried drawing a rectangle with text inside in a QGraphicsView. I get the text from the currently selected item in a QTreeWidget. The scene seems to sporadically show the text, sometimes it will, sometimes it won't.
void MainWindow::on_treewidget_itemSelectionChanged()
{
drawSectionFromProperties(ui->treewidget->currentItem());
}
void MainWindow::drawSectionFromProperties(QTreeWidgetItem *section)
{
ui->graphicsview->setScene(new QGraphicsScene());
ui->graphicsview->scene()->addRect(0,0,200,300,QPen(QColor(0,0,0)),QBrush(QColor(255,250,129)));
QFont objectTitle;
ui->graphicsview->scene()->addSimpleText(section->text(0),objectTitle);
}
Hmm, looks like you are creating a new scene on each item selection?
This isn't a very nice way to go :)
Better do the following:
Create an 'QGraphicsScene* m_scene;' and 'QGraphicsSimpleTextItem* m_textItem' data members in your MainWindow class private section.
In MainWindow::drawSectionFromProperties() do something like:
MainWindow::MainWindow(QWidget* parent, ...)
: m_scene(0), m_textItem(0)
{
...
}
// leave your on_treewidget_itemSelectionChanged as is
void MainWindow::drawSectionFromProperties(QTreeWidgetItem *section)
{
// setup things only ONE time on the first call
if(!m_scene)
{
m_scene = new QGraphicsScene();
ui->graphicsview->setScene(m_scene);
m_textItem = ui->graphicsview->scene()->addSimpleText(QString());
}
// here only change text of existing item
m_textItem->setText(section->text(0));
}
This way you won't be creating new scene on every item selection. Actually you need ONE scene and ONE item in it, no need to create them over and over and over again and stack one onto another like you currently do.
Cheers :)