I am trying to draw strings while I have a video palying, like a subtitle...
I have a Phonon::QVideoWidget, in its constructor I do:
painter = new QPainter(this);
and I have overrided the paint event to this, only for test:
void MyVideoWidget::paintEvent(QPaintEvent* event)
{
painter->drawLine(0, 0, 1, 1);
//painter-> anything shows
}
So when I start my player I see nothing that QPainter did, only the normal video playing
any ideas?
It is more common to make the QPainter a local instance in the paintEvent() function.
QPainter painter(this);
This results in the begin() and end() methods being called automatically. These are necessary for the QPainter to work correctly. You could try calling them manually in the paintEvent() to see if that makes a difference.
Another thing you might try for overlaying text on the video is to create a QLabel in code and make your video widget its parent. This does not require sub classing the video widget or overriding the paint event.
Related
I want to change a QWidget in a QMainWindow dynamically. Therefore, the old widget (if it exists) will be deleted, a new one will be constructed and added to the main window.
The widget (_visualization) is a QMainWindow itself that contains a menu bar and a widget that shows an OSG scene graph.
If I donĀ“t call show() on the new widget, I will only see the menu bar, but not the scene graph.
My goal is to call show(), when the user clicks on a button. The button is connected with the outer QMainWindow (MyQMainWindow).
Unfortunately, when I call show() on _visualization in the connected method, the scene graph will not be shown. In contrast to that, the scene graph will be shown, if I call it in the constructor method (loadVisualization(...)).
MyQMainWindow::MyQMainWindow(QWidget *parent ) :
QMainWindow(parent) {
...
loadVisualization(...);
connect(_ui->nextButton, SIGNAL(clicked()), this, SLOT(showNext()));
...
}
void MyQMainWindow::loadVisualization(QString filePath) {
if (_visualization) {
_heightWidgetLayout->removeWidget(_visualization);
delete _visualization;
}
_visualization= new HeightVisualization(0, filePath);
_visualization->setParent(_mainWindowWidget);
_heightWidgetLayout->addWidget(_visualization);
//_visualization->show(); // will work here
}
void MyQMainWindow::showNext() {
_visualization->show(); // does not work here!
}
I know that QT will call setVisible(...) on the widget. This method first tests some states in QT (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)). If I call show() in showNext(), these tests lead to a return without any change.
Is it a problem with connectors and slots? Is there a possibility to show the widget, when the user clicked on a button?
What I have learned is that it is easy to use stackedWidget.
You can then programmatically change it with this
currentPageIndex = (currentPageIndex + 1) % 3;
ui->stackedWidget->setCurrentIndex(0);
The 3 can be the total pages you have in your stack widget. You can either use currentPageIndex, or you can just create some constants with the page ids like I have done with the 0.
I've got some QGraphicsObjects which are dependent of the size of the scene they are on. So my graphics object needs to know when two events occur:
When it is added to the scene
When it's scene is resized
The way I do it now is - create 2 signals in scene's parent: obj_create, scene_resize. And connect them to the slots of the gr.object. It seems to be not the best way. I can't find any event like addedToScene or sceneResized in the QGraphcisItem...
Thanks much.
I would suggest one of two possible ways: Either subclass QObject in your GraphicsItem and simply use Signal/Slots or define your own interface, lets say IResizableEvent with a resize method. In your GraphicsItem you implement the method with your resize code. When you detect a scene resize in your Scene class, just iterate over all items, cast them to the interface type and call the resize method.
I just needed to read the doc little bit accurately... Hope it helps someone...
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == QGraphicsItem::ItemSceneHasChanged)
{
this->performSomeUpdates();
QObject::connect(this->scene(),SIGNAL(sceneRectChanged(QRectF)),this,SLOT(sceneRectChanged(QRectF)));
}
return QGraphicsItem::itemChange(change, value);
}
I can't figure out how to make centerOn() to move viewport around the item (or the item around the port, not sure which way it is).
The following code does work in main:
view.setDragMode(QGraphicsView::ScrollHandDrag);
view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setFrameStyle(QFrame::NoFrame);
view.showFullScreen();
QGraphicsPixmapItem *pmItem = new QGraphicsPixmapItem(pixMap);
scene.addItem(pmItem);
view.centerOn(QPointF(50,30));
view.show();
rc = qA.exec();
However, the centerOn() does nothing when I am trying to do the same from a paintEvent() of an overloaded QGraphicsView:
class MyView :: public QGraphicsView { ... }
void MyView::init(){
...
setDragMode(QGraphicsView::ScrollHandDrag);
setFrameStyle(QFrame::NoFrame);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_scene.clear();
setScene(&_scene);
super::showNormal();
}
void MyView::paintEvent(QPaintEvent *aEvent){
_scene.clear();
QGraphicsPixmapItem *pmItem = new QGraphicsPixmapItem(pixMap);
_scene.addItem(pmItem);
centerOn(QPointF(50.0, 30.0));
super::paintEvent(aEvent);
}
What do I miss?
Thank you
Alex
You basically pull the rug under the paintEvent call.
QGraphicsView communicates with QGraphicsScene by way of signals and slots. The scene has no chance to notify the view that a new item is just added to it since the actual paintEvent is called right after the creation. There's no event loop process between the 2 steps. So the paintEvent call doesn't have it setup properly for the new item, let alone the centering change.
And once the painting is finished, the view is validated and thinks it's all painted. So the it'll never update the area of the new item.
Call centerOn outside of any painting or updating event.
I solved this problem by placing a high value on setSceneRect.
Then I centralize the scene on an object or position.
example:
this->ui->graphicsView->setSceneRect (0,0,100000000, 100000000);
this->ui->graphicsView->centerOn(500,1030);
With the setSceneRect size GraphicsView does not work right.
Is there a way to show a popup when the user right clicks on an empty portion of the scene?
I'm new at Qt and I've tried slots and subclassing, but to no avail.
No such slot and, respectively:
"error: 'QMouseEvent' has not been declared"
when trying to implement the onMouseRelease event.
QGraphicsView is the widget used for displaying the contents of the QGraphicsScene. So the correct place to implement the context menu (popup menu) is the QGraphicsView.
You need to reimplement the contextMenuEvent function is your own class inherited from QGraphicsView:
void YourGraphicsView::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(this);
menu.addAction(...);
menu.addAction(...);
...
menu.exec(event->globalPos());
}
See also the Qt's Menus Example.
You can re-implement the contextMenuEvent method of the QGraphicsScene class, which will give you access to the scene coordinates as well as the screen coordinates (as opposed to QGraphicsView, which also works but doesn't have this information):
void YourGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
// event->scenePos() is available
QMenu menu(this);
menu.addAction(...);
menu.addAction(...);
...
menu.exec(event->screenPos());
}
I've derived from QGLWidget before, like so:
class MyGLWidget : public QGLWidget
{
public:
// stuff...
virtual void initializeGL() { /* my custom OpenGL initialization routine */ }
// more stuff...
};
However, I find that if I try to initialize a QGraphicsView with my custom QGLWidget as the viewport, initializeGL doesn't get called (setting a breakpoint within the Qt library, neither does QGLWidget::initializeGL() when created plain).
// initializeGL, resizeGL, paintGL not called
ui.graphicsView->setViewport(new MyGLWidget(QGLFormat(QGL::DoubleBuffer)));
// initializeGL, resizeGL, paintGL *still* not called
ui.graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::DoubleBuffer)));
Where is the correct location to place the code that currently resides in MyGLWidget::initializeGL()?
The setupViewport slot of a custom QGraphicsView could be used to call updateGL() on the QGLWidget, which will cause initializeGL() to be called.
class MyGraphicsView : public QGraphicsView
{
//... The usual stuff
protected slots:
virtual void setupViewport(QWidget *viewport)
{
QGLWidget *glWidget = qobject_cast<QGLWidget*>(viewport);
if (glWidget)
glWidget->updateGL();
}
};
So what I've found is QGraphicsView installs a custom eventFilter on your QGLWidget viewport so it never sees the initialize/resize/repaint events. This probably was done to make it work properly with drawBackground() etc.
My current best resolution is to catch the desired event either in QGraphicsView::resizeEvent()/etc, or install a custom eventFilter on your QGLWidget derived class to catch the resize/paint/etc events before QGraphicsView's custom eventFilter swallows them.
The pain, the pain, ... integrating widgets derived from QGlWidgets into QGraphicsView is no fun, of the parts of Qt that I know this is definitely one of the messier areas. I ended up using a part of kgllib (out of kde) called widgetproxy that is a very decent wrapper around a QGlWidget. I modified it to fit my needs but works reasonably well for most general cases where you want to use an exisiting class derived from QGlWidget inside a QGraphicsView and draw other things on top of it.
initializeGL() won't get called until the first call to either paintGL() or resizeGL() and not when the widget is constructed. This may happen as late as when the widget is first made visible.
I'm going to go ahead and answer my own question. This isn't optimal, but this is how I've gotten around the problem.
Instead of
ui.graphicsView->setViewport(new MyGLWidget(QGLFormat(QGL::DoubleBuffer)));
I've got this instead:
ui.graphicsView->setViewport(new QGLWidget(new CustomContext(QGLFormat(QGL::SampleBuffers))));
CustomContext is a class that derives from QGLContext. I've overridden the create member, like so:
virtual bool create(const QGLContext *shareContext = 0)
{
if(QGLContext::create(shareContext))
{
makeCurrent();
/* do my initialization here */
doneCurrent();
return true;
}
return false;
}
I don't think this is the optimal way to do this, but it's better than the alternative of not having a specific initialization step at all. I'd still be happy to have someone leave a better answer!