Ok, I've been able to get get Drag and Drop working on QGraphicsScene, but not QGraphicsView. My code looks something like this:
class GraphicsView : public QGraphicsView
{
public:
GraphicsView(QGraphicsScene *scene) : QGraphicsView(scene) {}
protected:
void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
event->setAccepted(true);
update();
}
void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
event->setAccepted(true);
update();
}
void dropEvent(QGraphicsSceneDragDropEvent *event)
{
//stuff that never runs...
update();
}
};
Although, this code works perfectly fine with QGraphicsScene inherited instead of QGraphicsView. I also ran the setAcceptDrops(true) function. What am I doing wrong?
Related
When I'm using a QTreeWidget (via qdesigner) with the dragDropMode set to InternalMove and then attempt to move one of the items, the scrollbar snaps back to the original position of the item I moved. I would like the scrollbar to stay at the position the item was dropped. Is there an easy way to do that? I adjusted the defaultDropAction, but to no avail.
Figured it out...
class MyTree : public QTreeWidget
{
Q_OBJECT
public:
MyTree(QWidget *parent = 0);
signals:
void verticalScrollBarValue(int val);
protected slots:
void setTreeVerticalScroll(int val);
protected:
void dropEvent(QDropEvent *event);
};
MyTree::MyTree(QWidget *parent) : QTreeWidget(parent)
{
connect(this, &MyTree::verticalScrollBarValue,
this, &MyTree::setTreeVerticalScroll);
}
void MyTree::setTreeVerticalScroll(int val)
{
verticalScrollbar()->setValue(val);
}
void MyTree::dropEvent(QDropEvent *event)
{
int v = verticalScrollbar()->value();
QTreeWidget::dropEvent(event);
emit verticalScrollBarValue(v);
}
Disclaimer: There may be a typo in there somewhere, I can't copy directly from my work environment.
I have created a Qwidget with a QRect. Now I would like to move this Rect with my keyboard. Which does not work. When trying with a mousePressEvent instead of the keyPressEvent, everything is working fine though. There are no Focuses yet set, which probably is the problem here. But it's the first time I have to work with those and I just can't figure out what to do and how to use them, even after searching online for the last hours.
I tried putting setFocusPolicy(Qt::StrongFocus) in my widgets constructor amongst other things, but nothing has worked so far. Maybe I'm just blind to an obvious solution, but please help? Thanks alot already
my paint event:
void zeichenFeld::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin (this);
//Avatar:
QRect rectAv=QRect(xAv, yAv, 20,20);
painter.fillRect(rectAv, Qt::BrushStyle::SolidPattern);
painter.fillRect(rectAv, colorAv);
painter.drawRect(rectAv);
painter.end();
}
void zeichenFeld::keyPressEvent(QKeyEvent *event)
{
if(event->key()==Qt::Key_A){
xAv-=10;
}
if(event->key()==Qt::Key_D){
xAv+=10;
}
update();
}
void zeichenFeld::mousePressEvent(QMouseEvent *event){
if(event->button()==Qt::LeftButton)
{
xAv-=25;
}
if(event->button()==Qt::RightButton)
{
xAv+=25;
}
update();
}
header:
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent *event);
void mousePressEvent(QMouseEvent *event);
Edit: i simply added the setFocusPolicy(Qt::StrongFocus); to the wrong contructor. Working now
a QRect is not a visual class, so if you used the PaintEvent to draw a rectangle, then you need to come up with your special way to handle that in the mouse press event.
something like:
YourClass.h
protected:
void mousePressEvent(QMouseEvent *ev) override;
void mouseMoveEvent(QMouseEvent *ev) override;
void mouseReleaseEvent(QMouseEvent *ev) override;
private:
QRect _myRect;
YourClass.cpp
void YourClass::mousePressEvent(QMouseEvent *ev) {
if (_myRect.contains(ev->localPos())){
_isRectSelected = true;
}
}
void YourClass::mouseMoveEvent(QMouseEvent *ev) {
if (_isRectSelected) {
_myRect->setX(ev->localPos().x());
_myRect->setY(ev->localPos().y());
}
}
void YourClass::mouseReleaseEvent(QMouseEvent *ev) {
if (_isRectSelected) {
_isRectSelected = false;
}
}
but I wouldn't reccomend that. Try to use QGraphicsView with QGraphicsRectItem as it's a visual class. it knows how to paint itself and it also has mouse handling.
Or even better, Qml.
I dont understand what`s going on: when i create QGraphicsView object directly and adding scene with a pixmap, all is ok, pixmap appears on the screen:
scene.addPixmap(pix);
QGraphicsView graphicsView;
graphicsView.setScene(&scene);
But when i try to inherit QGraphicsView class with purpose of reimplementing events, nothing happend and i got white screen without pixmap, but events like changing cursor is working:
scene.addPixmap(pix);
DrawArea graphicsView;
graphicsView.setScene(&scene);
.h file:
class DrawArea : public QGraphicsView
{
Q_OBJECT
public:
DrawArea(QWidget *parent = 0);
~DrawArea();
signals:
public slots:
void mousePressEvent(QMouseEvent * e);
void paintEvent(QPaintEvent *);
void enterEvent(QEvent *e);
private:
QPoint coord;
};
.cpp file:
DrawArea::DrawArea(QWidget *parent)
: QGraphicsView(parent){
}
DrawArea::~DrawArea(){
}
void DrawArea::mousePressEvent(QMouseEvent * event){
}
void DrawArea::paintEvent(QPaintEvent *event){
}
void DrawArea::enterEvent(QEvent *event){
viewport()->setCursor(Qt::CrossCursor);
}
Tell me if something missed, Thanks in advance.
You should process your events. Try this:
void DrawArea::mousePressEvent(QMouseEvent * event)
{
//some actions
QGraphicsView::mousePressEvent(event);
}
void DrawArea::paintEvent(QPaintEvent *event)
{
//some actions
QGraphicsView::paintEvent(event);
}
Also I think that you don't need paintEvent at all, do all needed things in the scene.
I'm trying to make a simple draggable item using the graphics framework. Here's the code for what I did so far:
Widget class:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
};
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
DragScene *scene = new DragScene();
DragView *view = new DragView();
QHBoxLayout *layout = new QHBoxLayout();
DragItem *item = new DragItem();
view->setAcceptDrops(true);
scene->addItem(item);
view->setScene(scene);
layout->addWidget(view);
this->setLayout(layout);
}
Widget::~Widget()
{
}
DragView class:
class DragView : public QGraphicsView
{
public:
DragView(QWidget *parent = 0);
};
DragView::DragView(QWidget *parent) : QGraphicsView(parent)
{
setRenderHints(QPainter::Antialiasing);
}
DragScene class:
class DragScene : public QGraphicsScene
{
public:
DragScene(QObject* parent = 0);
protected:
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
void dropEvent(QGraphicsSceneDragDropEvent *event);
};
DragScene::DragScene(QObject* parent) : QGraphicsScene(parent)
{
}
void DragScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event){
}
void DragScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event){
}
void DragScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event){
}
void DragScene::dropEvent(QGraphicsSceneDragDropEvent *event){
qDebug() << event->pos();
event->acceptProposedAction();
DragItem *item = new DragItem();
this->addItem(item);
// item->setPos(event->pos()); before badgerr's tip
item->setPos(event->scenePos());
}
DragItem class:
class DragItem : public QGraphicsItem
{
public:
DragItem(QGraphicsItem *parent = 0);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
protected:
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};
DragItem::DragItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
setFlag(QGraphicsItem::ItemIsMovable);
}
QRectF DragItem::boundingRect() const{
const QPointF *p0 = new QPointF(-10,-10);
const QPointF *p1 = new QPointF(10,10);
return QRectF(*p0,*p1);
}
void DragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
if(painter == 0)
painter = new QPainter();
painter->drawEllipse(QPoint(0,0),10,10);
}
void DragItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event){
}
void DragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
}
void DragItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
QMimeData* mime = new QMimeData();
QDrag* drag = new QDrag(event->widget());
drag->setMimeData(mime);
drag->exec();
}
void DragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
}
main.cpp instantiates a Widget and shows it. When I try to drag the circle, the app just creates another circle over the original one, regardless of where I release the drag. qDebug() in DragScene's dropEvent() shows QPointF(0,0) everytime the drag ends. I'm having a hard time trying to understand exactly what I have to do, which classes I should subclass, which methods needs to be overriden, to make this work. The documentation on this isn't very detailed. I'd like to know how to make this work, and if there's some other, more comprehensive resource to learn about the graphics view framework, besides the official documentation (which is excellent btw, but it would be great if there was a more detailed treatise on the subject).
EDIT:
Following badgerr's advice, I replaced item->pos() in DragScene::dropEvent() with item->scenePos(), now the drop event creates a new circle in the drop site, which is more or less what I wanted. But the original circle is still in place, and while the drag is in progress, the item doesn't follow the mouse cursor.
The QGraphicsSceneDragDropEvent documentation says that pos() should return the cursor position in relation to the view that sent the event, which, unless I got it wrong, shouldn't be (0,0) all the time. Weird.
I've read in a forum post that you can use QDrag::setPixMap() to show something during the drag, and in examples I've seen pictures being set as pixmaps, but how do I make the pixmap just like the graphics item I'm supposed to be dragging?
There is an example with Qt Assistant called the "Drag and Drop Robot Example" which appears to use the QDrag method, I don't know if you've had a look at that already.
edit: Just a quick observation, you appear to be creating a new DragItem in your DropEvent, instead of using the mimeData() of the event itself, and since your item draws itself at 0,0, that might explain why you have a new one appearing at that position regardless of where you drop your DragItem.
When I wrote a graphics dragging thing similar to this, I went about it a slightly different way. Maybe it will help you:
Instead of using the QDrag stuff, I used only the mousePressEvent, mouseReleaseEvent, and mouseMoveEvent functions of QGraphicsItem. The mouse press/release set a flag indicating the drag state, and move followed a process of
call prepareGeometryChange();
update the bounds of the QGraphicsItem (my boundingRect() function returns these bounds. All my graphics item bounds are in QGraphicsScene space)
call update();
Then in my paint() function I draw a shape using the boundingRect().
Sorry I don't have a code sample to share, I'll knock one up if I get time.
I make a simple window with wxwidgets. How can I change the border?
Also how can I call the destroy function(OnClose) with the right arrow button press?
#include <wx/wx.h>
class _Frame: public wxFrame
{
public:
_Frame(wxFrame *frame, const wxString& title);
private:
void OnClose(wxCloseEvent& event);
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(_Frame, wxFrame)
END_EVENT_TABLE()
_Frame::_Frame(wxFrame *frame, const wxString& title)
: wxFrame(frame, -1, title)
{}
void _Frame::OnClose(wxCloseEvent &event)
{
Destroy();
}
class _App : public wxApp
{
public:
virtual bool OnInit();
};
IMPLEMENT_APP(_App);
bool _App::OnInit()
{
_Frame* frame = new _Frame(0L, _("wxWidgets Application Template"));
frame->Show();
return true;
}
To close the window on right-arrow you need to trap EVT_CHAR or EVT_KEY_DOWN like so:
header file:
void OnChar(wxKeyEvent& event);
source file:
void _Frame::OnChar(wxKeyEvent& event)
{
if (event.GetKeyCode() == WXK_RIGHT)
{
wxCommandEvent close(wxEVT_CLOSE_WINDOW);
AddPendingEvent(close);
}
event.Skip();
}
BEGIN_EVENT_TABLE(_Frame, wxFrame)
EVT_CHAR(_Frame::OnChar)
END_EVENT_TABLE()
Changing the border (by setting a different wxBORDER_XXX style) doesn't work for all windows/under all platforms after the initial window creation so you'd better recreate the window if you really, really need to do this.