C++ public and private classes, with screen movements? - c++

I am stuck, I need help, I can't post all files here because this is a project with almost 20 files of c++. But it basically all boils down to movements on a screen.
-The class "MyClass" is the screen, it has a constructor which calls the functions. the screen has a small-box at the bottom. when you press the mouse down,up, or move it, it sends a signal or 'Event" and one of the three functions below is called;
-function-mouseMotion, it should move the small-box to where your mouse is pointing when you are moving the mouse, sort of drag. this function should be active whenever you press down your mouse, say whenever mouse is down
-function-mouseButtonDown, when u press your mouse down, the small-box should move from the bottom of screen to where your cursor is.
-function-mouseButtonUp, when you unclick your mouse, this function will be called and all the movements of small box should stop.
Right now as the code is, whenever I bring the ouse to the screen, the small box immediately jumps and starts following the mouse. But our professor wants us to change the functions such that when I introduce the moue on the screen, nothing should happen. When I click down the mouse, the box should then come to where the mouse is. If I click and hold the mouse down as I move it, the box should keep following the mouse. Finally, if i unclick the mouse, the box needs to remain where i unclicked it from.
What alograithm would you use, am new to c++
using namespace WALY;
class MyClass : public Frame {
private:
void(*switchAction) (void);
Frame* box;
static void mouseButtonDown (Frame* f, const Event* e);
static void mouseButtonUp (Frame* f, const Event* e);
static void mouseMotion (Frame* f, const Event* e);
public:
MyClass (Frame* parent, void (*switchFunc) (void));
void activate (void);
void deactivate (void);
};
MyClass::MyClass(Frame *parent, void (*switchFunc)(void)) : Frame (parent), switchAction (switchFunc)
{
box = new Frame (this, 250, 700); // creating the box on the screen
box->setAlign (ALIGN_C);
Rect boxRect;
boxRect.x = boxRect.y = 0;
boxRect.w = 80;
boxRect.h = 50;
box->setScrollRect (boxRect);
box->useSolidBackground (0x808080);
setCallbackFunc (MOUSE_DOWN, mouseButtonDown); // registering functions into wally library
setCallbackFunc (MOUSE_UP, mouseButtonUp);
setCallbackFunc (MOUSE_MOTION, mouseMotion);
deactivate ();
}
void MyClass::activate(void)
{
setActive(true);
setVisible(true);
}
void MyClass::deactivate(void)
{
setVisible(false);
setActive(false);
}
void
MyClass::mouseMotion (Frame* f, const Event* e)
{
MyClass* wywtcyc = (MyClass*)f;
wywtcyc->box->setX (e->motion.x);
wywtcyc->box->setY (e->motion.y);
}
void MyClass::mouseButtonDown (Frame* f, const Event* e)
{
// (e->button.x)
}
void MyClass::mouseButtonUp (Frame* f, const Event* e)
{
}

The logic could be like below:
Declare variables:
mouseIsDown = False;
released = False;
In mouseMotion:
if (mouseIsDown && ! released) {
// your current code
}
In mouseButtonDown:
if (mouseIsDown) {
released = True;
} else {
mouseIsDown = True;
released = False;
}
In mouseButtonUp:
if (mouseIsDown) {
mouseIsDown = False;
released = True;
}

Related

How to show a QToolTip on mouse press event and leave it popped up for some time? Qt

Trying to show a tool tip on mouse press event and make it popped up for some time. For now it shows only if a mouse button is pressed.
void ::mousePressEvent(QMouseEvent* e)
{
if (!m_isLinkingAvailable)
{
QToolTip::showText(e->screenPos().toPoint(),
tr("Symbol Linking\navailable only for Price"), this);
}
}
According to the Qt Docs, looks like there's an alternate method for this function:
void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
You should be able to specify a time for how long to display the tooltip.
EDIT:
Okay so seems like this method doesn't work as expected with a mousePress event, so here's an alternative using a QTimer:
Add these to your class:
MyConstructor(...params...)
, m_tooltipTimer(new QTimer(this)) // don't forget this line
{
connect(m_tooltipTimer, SIGNAL(timeout()), this, SLOT(updateTooltip()));
setAcceptedMouseButtons(Qt::AllButtons);
}
...
public slots:
void mousePressEvent(QMouseEvent *event) override;
void updateTooltip();
...
private:
QPoint m_tooltipPos;
qint64 m_tooltipTimerStart;
QTimer *m_tooltipTimer;
And then implement these in your .cpp
void ::mousePressEvent(QMouseEvent *event) {
m_tooltipTimer->start(200); // 5x per second, automatically resets timer if already started
m_tooltipTimerStart = QDateTime::currentMSecsSinceEpoch();
m_tooltipPos = event->globalPos();
event->accept();
}
void ::updateTooltip() {
auto howLongShown = QDateTime::currentMSecsSinceEpoch() - m_tooltipTimerStart; // startTime here is the moment of first showing of the tooltip
qDebug() << howLongShown;
if (howLongShown < 1000) { // 1 sec
QToolTip::showText(m_tooltipPos, tr("Test Tooltip")); // Replace this with your own
} else {
QToolTip::hideText();
m_tooltipTimer->stop();
}
}
Thanks to #Ian Burns's answer I have manged to create own approach:
void ::mousePressEvent(QMouseEvent*)
{
QTimer::singleShot(200, [this]()
{
QToolTip::showText(mapToGlobal({}),
tr("Symbol Linking\navailable only for Price"), this);
});
}
Somehow if I show a tooltip inside mousePressEvent method it disappears immediately after I unpress the mouse button. QTimer delays the pop up call and it stays popped for reasonable time.

How to connect buttons with methods, which will be called on click

I started programming some custom gui application. But i need to know how to connect button with some method.
For example i have:
class Button
{
private:
string Text;
/*etc*/
public:
string GetLabel();
void SetLabel(string label);
void Connect(/*method name as param*/)
{
//TODO -this is that thing i need help here
/*this is method for connecting button with method, which will be
called on click, which im asking for help*/
}
};
class Window
{
private:
int sizeX,sizeY;
public:
void Put(Button * button,int _hpos,int _vpos);
void Show();
/*etc */
};
class MyWindow : public Window
{
public:
MyWindow()
{
InitializeComponents();
}
void Run()
{
this -> Put(btn1,10,10); //put button in window at position 10,10
this -> Show();
}
private:
Button * btn1;
void InitializeComponents()
{
btn1 = new Button();
btn1 -> Connect(on_btn1_click); //select which method will be called when user click this button, which I dont know how to do so pls help
}
void on_btn1_click() //this method is called when user click the button
{
//do something if user clicked btn1
}
};
int main()
{
MyWindow * win1 = new MyWindow();
win1 -> Run();
return 0;
}
So there is private method inside MyWindow class which will be called when user clicks the button (btn1). Method Connect() selects which method will be used for calling when user clicks the button.
You can check if the mouse is over a button/UI object, If it is than trigger a command/event.
const Button& GetObjectBelowMouse(int xMousePos, int yMousePos) // This would be equavalent to your Connect type
{
// all buttons would be your container of buttons / GUI objects.
for( const auto& button : allButtons)
{
// top,bottom,left,right would be the bounding rectangle that encapsulates the coordinates of the object
if( (xMousePos > button.left && xMousePos < button.right ) && (yMousePos > button.bottom && yMousePos < buttom.top))
{
return button;
}
}
// in this case we have a different constructor that creates a "empty" button that has no function
return Button(NO_OBJECT);
}
// the usage would be something like
int main()
{
/*
.. create button, set it's possition, etc
*/
// Option 1
if(GetObjectBelowMouse(mouse.x, mouse.y).type != NO_OBJECT)
{
// Do whatever you want, you know that the user has clicked a valid object
button.Foo();
}
// Option 2
GetObjectBelowMouse(mouse.x, mouse.y).Foo(); // You know that every button has a foo object, and that NO_OBJECT has a foo that does nothing, so you don't need to compare if it is NO_OBJECT or not.
}

Select an area from an image using a draggable rectangle using wxwidget in c++

I have written a program in c++ using wxwidgets.I am placing a rectangle on the image and want to select the part of image covered by rectangle for which the rectangle should be draggable. But the problem is when I click the mouse the image vanishes and the only rectangle (which can be dragged) remains and it happens vice-versa.
`
class BasicDrawPane : public wxPanel
{
public:
BasicDrawPane();
BasicDrawPane(wxFrame* parent);
void paintEvent(wxPaintEvent & evt);
void render(wxDC& dc);
void mouseMoved(wxMouseEvent& event);
void mouseDown(wxMouseEvent& event);
void mouseWheelMoved(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void rightClick(wxMouseEvent& event);
void mouseLeftWindow(wxMouseEvent& event);
DECLARE_EVENT_TABLE()
};
class MyFrame: public wxFrame{
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
wxString path;
BasicDrawPane panel;
private:
void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void OnOpen(wxCommandEvent& event);
void OnPaint(wxCommandEvent& event);
void OnRect(wxCommandEvent& event);
void OnSave(wxCommandEvent& event);
DECLARE_EVENT_TABLE();
wxBitmap bmp;
wxMemoryDC memDC;
};
enum
{
ID_Hello = 1, ID_PAINT = 2, ID_RECT = 3, ID_SAVE = 4
};
BEGIN_EVENT_TABLE( MyFrame, wxFrame )
EVT_MENU(ID_Hello,MyFrame::OnHello)
EVT_MENU(wxID_EXIT,MyFrame::OnExit)
EVT_MENU(wxID_ABOUT,MyFrame::OnAbout)
EVT_MENU(wxID_OPEN,MyFrame::OnOpen)
EVT_MENU(ID_PAINT,MyFrame::OnPaint)
EVT_MENU(ID_RECT,MyFrame::OnRect)
EVT_MENU(ID_SAVE,MyFrame::OnSave)
END_EVENT_TABLE()
void MyFrame::OnPaint(wxCommandEvent& event)
{
//wxPaintDC dc( this );
//dc.DrawBitmap( m_bitmap, 0, 0, true /* use mask */ );
//wxStaticBitmap *b1 = new wxStaticBitmap(this, -1, wxBitmap(wxImage(path)));
bmp.LoadFile((path),wxBITMAP_TYPE_ANY);
// bmp.LoadFile((path),wxBITMAP_TYPE_PNG);
memDC.SelectObject( bmp );
//memDC.SetBackground(*wxWHITE_BRUSH);
//memDC.Clear();
/* memDC.SetPen(*wxGREEN_PEN);
memDC.SetBrush(*wxTRANSPARENT_BRUSH);
memDC.DrawRectangle( m_x, m_y, WIDTH, HEIGHT );*/
//Check();
memDC.SelectObject(wxNullBitmap);
// wxSize sz(512,384);
// wxSize sz(900,600);
wxStaticBitmap *b1 = new wxStaticBitmap(/* dynamic_cast<wxFrame*>*/this, -1, bmp, wxDefaultPosition);
Refresh();
}
class MyApp: public wxApp
{
public:
virtual bool OnInit();
//MyFrame *frame;
BasicDrawPane * drawPane;
};
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
// wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
//frame = new MyFrame((wxFrame *)NULL, -1, wxT("Hello wxDC"), wxPoint(50,50), wxSize(800,600));
MyFrame *frame = new MyFrame( _T("Hello World"), wxPoint(50, 50), wxSize(600, 600) );
// drawPane = new BasicDrawPane( (wxFrame*) frame );
// sizer->Add(drawPane, 1, wxEXPAND);
//frame->SetSizer(sizer);
// /* dynamic_cast<wxFrame*>(this)*/ frame-> SetAutoLayout(true);
/* dynamic_cast<wxFrame*>(this)*/frame -> Show();
return true;
}
BEGIN_EVENT_TABLE(BasicDrawPane, wxPanel)
EVT_MOTION(BasicDrawPane::mouseMoved)
EVT_LEFT_DOWN(BasicDrawPane::mouseDown)
EVT_LEFT_UP(BasicDrawPane::mouseReleased)
EVT_RIGHT_DOWN(BasicDrawPane::rightClick)
EVT_LEAVE_WINDOW(BasicDrawPane::mouseLeftWindow)
EVT_MOUSEWHEEL(BasicDrawPane::mouseWheelMoved)
EVT_PAINT(BasicDrawPane::paintEvent)
// catch paint events
END_EVENT_TABLE()
void BasicDrawPane::mouseDown(wxMouseEvent& event)
{
/* if (event.GetPosition().x >= m_x && event.GetPosition().x <= m_x + WIDTH &&
event.GetPosition().y >= m_y && event.GetPosition().y <= m_y + HEIGHT)
{
m_dragging = true;
m_previous_mouse_x = event.GetPosition().x;
m_previous_mouse_y = event.GetPosition().y;
}*/
}
void BasicDrawPane::mouseWheelMoved(wxMouseEvent& event) {}
void BasicDrawPane::mouseReleased(wxMouseEvent& event)
{
m_dragging = true;
}
void BasicDrawPane::mouseMoved(wxMouseEvent& event)
{
if (m_dragging && event.Dragging())
{
int delta_x = event.GetPosition().x - m_previous_mouse_x;
int delta_y = event.GetPosition().y - m_previous_mouse_y;
m_x += delta_x;
m_y += delta_y;
m_previous_mouse_x = event.GetPosition().x;
m_previous_mouse_y = event.GetPosition().y;
// trigger paint event
Refresh();
}
}
void BasicDrawPane::mouseLeftWindow(wxMouseEvent& event)
{
m_dragging = true;
}
void BasicDrawPane::rightClick(wxMouseEvent& event) {}
BasicDrawPane::BasicDrawPane(wxFrame* parent) :
wxPanel(parent)
{
// m_dragging = true;
// m_x = 100;
// m_y = 100;
}
/*
* Called by the system of by wxWidgets when the panel needs
* to be redrawn. You can also trigger this call by
* calling Refresh()/Update().
*/
void BasicDrawPane::paintEvent(wxPaintEvent & evt)
{
//wxCommandEvent w1(wxEVT_NULL, ID_PAINT);
//OnPaint(w1);
wxPaintDC dc(this);
render(dc);
}
void BasicDrawPane::render(wxDC& dc)
{
dc.SetPen(*wxGREEN_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle( m_x, m_y, WIDTH, HEIGHT );
}
`
There are several things to explain in order to answer this question, so I will take them one at a time. I think your basic idea is okay, so I won't go into a lot of detail on how the actual selection should take place etc.
Firstly, I would recommend to use either Connect() or Bind() instead of an event table. This allows you to connect child window events back to the parent window and handle them all in one place.
For example, if your main frame class is called MainFrame and you have a wxPanel member called m_DrawPanel, in the MainFrame ctor you could have:
MainFrame::MainFrame(wxWindow* parent)
{
// Connect mouse event handlers.
m_DrawPanel->Connect(wxEVT_LEFT_DOWN,
wxMouseEventHandler(MainFrame::OnPanelLDown), NULL, this);
m_DrawPanel->Connect(wxEVT_LEFT_UP,
wxMouseEventHandler(MainFrame::OnPanelLUp), NULL, this);
m_DrawPanel->Connect(wxEVT_MOTION,
wxMouseEventHandler(MainFrame::OnPanelMotion), NULL, this);
// Connect paint and erase handlers.
m_DrawPanel->Connect(wxEVT_PAINT,
wxPaintEventHandler(MainFrame::OnPanelPaint), NULL, this);
m_DrawPanel->Connect(wxEVT_ERASE_BACKGROUND,
wxEraseEventHandler(MainFrame::OnPanelErase), NULL, this);
// Load the bitmap and set the mode to 'not currently selecting'.
m_Picture.LoadFile ("wxwidgets.png", wxBITMAP_TYPE_PNG);
m_SelectionMode = false;
}
Note: I included a wxEVT_ERASE_BACKGROUND event override because otherwise panels tend to be cleared which leads to flicker (this is one simple approach).
The 3 mouse event handlers can implement your selection logic (I think this is basically what you are intending already):
void MainFrame::OnPanelLDown(wxMouseEvent& event)
{
m_SelectionMode = true;
m_SelectionRect = wxRect(event.GetPosition(), wxSize(0, 0));
}
void MainFrame::OnPanelLUp(wxMouseEvent& event)
{
m_SelectionMode = false;
// ... handle what to do with the selection here
// (selected area is defined by m_SelectionRect).
// ...
// Zero the selection rectangle for neatness (not really required).
m_SelectionRect = wxRect ();
}
void MainFrame::OnPanelMotion(wxMouseEvent& event)
{
m_SelectionRect = wxRect(m_SelectionRect.GetTopLeft(), event.GetPosition());
// Call Refresh() to trigger a paint event.
m_mainPanel->Refresh();
}
As mentioned earlier, override the panel's wxEVT_ERASE_BACKGROUND event to do nothing:
void MainFrame::OnPanelErase(wxEraseEvent& event)
{
}
Finally, I think this is the bit that you really are asking in your question (I included the others to help you build a working program):
void MainFrame::OnPanelPaint(wxPaintEvent& event)
{
// Obtain a wxPaintDC.
wxPaintDC pdc (m_mainPanel);
// Draw our image.
pdc.DrawBitmap(m_Picture, wxPoint(0, 0));
// If the user is currently selecting (left mouse button is down)
// then draw the selection rectangle.
if (m_SelectionMode)
{
pdc.SetPen(*wxRED_PEN);
pdc.SetBrush(*wxTRANSPARENT_BRUSH);
pdc.DrawRectangle(m_SelectionRect);
}
}
This is a paint event handler, so first we need to create a wxPaintDC context. Next, we paint the bitmap, this ensures it is refreshed every time and not damaged by mouse movements, resizing or other windows being dragged etc. Finally, if the user is currently moving the mouse with the left button pressed, then draw the selection rectangle.
There are many other ways of achieving the same thing. Some of them are possibly better, or more efficient, however this is a simple working way until you become more familiar with wxWidgets.

cocos2d-x touch handling with layers

I have a problem with cocos2d-x touch handler. I have two classes. Each class has one scene and one layer.I have sprites on both layers, and they handle in the same function. The problem is when I make the transition from layer A to layer B and click on the sprite, so touch handler gets sprite from layer A, but I need sprite from layer B, obviously that I click on layer B. As far as I understood, the problem is in setPriority? Could you please help me solve this problem? Thanks
CardItem is my sprite
void CardItem::addEvents()
{
auto listener = cocos2d::EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [&](cocos2d::Touch* touch, cocos2d::Event* event)
{
cocos2d::Vec2 p = touch->getLocation();
cocos2d::Rect rect = this->getBoundingBox();
if(rect.containsPoint(p))
{
return true; // to indicate that we have consumed it.
}
return false; // we did not consume this event, pass thru.
};
listener->onTouchEnded = [=](cocos2d::Touch* touch, cocos2d::Event* event)
{
//I have here some code
};
cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listener, 30);
}
void CardItem::touchEvent(cocos2d::Touch* touch, cocos2d::Vec2 _point)
{
auto *pNode = this->getParent(); // here is "pNode" always gets layer A
}
that's how I change scenes beetween layer A and B
void GameBoardLayer::showGameBoardComputer()
{
pGameBoardComputerScene = GameBoardComputerScene::create();
auto pGameBoardComputerLayer = pGameBoardComputerScene->getLayer();
Director::getInstance()->pushScene(pGameBoardComputerScene);
}
void GameBoardComputerLayer::gameBoardComputerItemBackCallback(Ref* pSender)
{
Director::getInstance()->popScene();
}
so when I click on sprite no matter what layer it is, it always clicks on layer A through layer B

Repositioning a label with mouseevents to anywhere on the screen

I've created a label and used setPixmap to attach a .png image to the label. I've also setWindowFlags to disable the title bar and create a frameless window. Because I've disabled those, it also disables the ability to drag anything around, so I want to create mouseevents (unless there's a better method) to position my label anywhere on the screen exactly like dragging the frame of a window. How would I do that? An example and brief explanation would be greatly appreciated.
reimplement the QMouseEvents you need .... like
void MyLabel::mousePressEvent(QMouseEvent* e)
{
m_moveDatWidget = true;
// so when the mousebutton got pressed, you set something to
// tell your code to move the widget ... consider maybe you
// want to move it only on right button pressed ...
}
void MyLabel::mouseReleaseEvent(QMouseEvent* e)
{
m_moveDatWidget = false;
// after releasing do not forget to reset the movement variable
}
void MyLabel::mouseMoveEvent(QMouseEvent* e)
{
// when in 'moving state' ...
if (m_moveDatWidget)
{
// move your widget around using QWidget::move(qreal,qreal)
}
}
this is only a really basic implementation but it should do well if you calculate the desired movement correct :)
I would implement the label dragging by mouse in the following way:
class Label : public QLabel
{
public:
// Implement the constructor(s)
protected:
void Label::mouseMoveEvent(QMouseEvent* event)
{
if (!m_offset.isNull()) {
move(event->globalPos() - m_offset);
}
QLabel::mouseMoveEvent(event);
}
void Label::mousePressEvent(QMouseEvent* event)
{
// Get the mouse offset in the label's coordinates system.
m_offset = event->globalPos() - pos();
QLabel::mousePressEvent(event);
}
void Notifier::mouseReleaseEvent(QMouseEvent* event)
{
m_offset = QPoint();
QLabel::mouseReleaseEvent(event);
}
private:
// The mouse pointer offset from the top left corner of the label.
QPoint m_offset;
};