Felhasználói eszközök

Eszközök a webhelyen


oktatas:programozas:wxwidgets:wxwidgets_kezikoenyv:esemenyek

Ez a dokumentum egy előző változata!


< wxWidgets kézikönyv

Események

Az események minden grafikus felhasználói felülettel (GUI-val) rendelkező program része. Minden GUI program eseményeken keresztül van vezérelve. Egy alkalmazás reagál a különböző eseménytípusokra, amely a futása során generálódnak. Az eseményeket főleg a felhasználó generálja. De az események máshonnan is származhatnak. Például a internet kapcsolat, ablakkezelő, időzítő, stb. Amikor egy alkalmazás elindul egy fő eseményhurok keletkezik. Az alkalmazások a fő eseményhurkon ülnek és várják a létrejövő eseményeket. A fő eseményhurok megszűnik, amikor kilépünk az alkalmazásból.

Definíciók

Az események az alkalmazások szintjén az információcsere alapvető eszközei. A GUI alkalmazás tipikusan ilyen. Az eseményhurok egy programozói eszköz az események és üzenetek figyelésére egy programban. Az esemény hurok folyamatosan, újra és újra feldolgozza az eseményeket. A program diszpécsere összeköti az eseményeket az eseménykezelőkkel. Az eseménykezelők metódusok, amelyek reagálnak az eseményekre.

Az esemény objektum az eseményt kiváltó objektum. Ez alap szinten egy ablak. Az esemény típusa elárulja, hogyan keletkezett.

Egy egyszerű esemény példa

Az események kezelésének hagyományos módja a wxWidgetsben a statikus eseménytáblák használata. Ez az MFC hatása volt. A sok rugalmasságot nyújtó modern módszer a Connect() metódus használata. Mivel ez a módszer jobb mint az eseménytábla, ezért wxWidgets oktatóanyagban ezt fogjuk használni.

Eseménytábla

A következő példában az eseménytábla használatát mutatjuk be.

button.h
#include <wx/wx.h>
 
class MyButton : public wxFrame
{
  public:
      MyButton(const wxString& title);
 
      void OnQuit(wxCommandEvent& event);
 
  private:
      DECLARE_EVENT_TABLE()
 
};
button.cpp
#include "button.h"
 
MyButton::MyButton(const wxString& title)
         : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 150))
{
 
    wxPanel *panel = new wxPanel(this, wxID_ANY);
    wxButton *button = new wxButton(panel, wxID_EXIT, 
        wxT("Quit"), wxPoint(20, 20));
 
    Centre();
 }
 
void MyButton::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}
 
BEGIN_EVENT_TABLE(MyButton, wxFrame)
      EVT_BUTTON(wxID_EXIT,  MyButton::OnQuit)
END_EVENT_TABLE()
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
    public:
      virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "button.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
 
      MyButton *button = new MyButton(wxT("Button"));
      button->Show(true);
 
      return true;
}

A példánkban készítünk egy egyszerű nyomógombot. A nyomgombra klikkelés bezárja az alkalmazást.

  private:
      DECLARE_EVENT_TABLE()

A header fájlba deklaráljuk egy eseménytáblát a DECLARE_EVENT_TABLE() makróval.

  BEGIN_EVENT_TABLE(MyButton, wxFrame)
      EVT_BUTTON(wxID_EXIT,  MyButton::OnQuit)
  END_EVENT_TABLE()

Meghatároztunk egy eseménytáblát minden tagfüggvény számára.

Példa a Connect() használatára

Ebben a részben a mozgásos eseményekről lesz szó. A mozgásos események információkat tartalmaznak a változásokról. Egy mozgásos esemény akkor generálódik, amikor egy ablakot pozicionálunk. A mozgásos eseményeket a wxMoveEvent osztály tartalmazza. A wxEVT_MOVE egy eseménytípus.

move.h
#include <wx/wx.h>
 
class Move : public wxFrame
{
public:
    Move(const wxString& title);
 
    void OnMove(wxMoveEvent & event);
 
    wxStaticText *st1;
    wxStaticText *st2;
 
};
move.cpp
#include "move.h"
 
Move::Move(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
    wxPanel *panel = new wxPanel(this, -1);
 
    st1 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 10));
    st2 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 30));
 
    Connect(wxEVT_MOVE, wxMoveEventHandler(Move::OnMove));
 
    Centre();
}
 
void Move::OnMove(wxMoveEvent& event)
{
    wxPoint size = event.GetPosition();
    st1->SetLabel(wxString::Format(wxT("x: %d"), size.x ));
    st2->SetLabel(wxString::Format(wxT("y: %d"), size.y ));
}
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
    public:
      virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "move.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
      Move *move = new Move(wxT("Move event"));
      move->Show(true);
 
      return true;
}

A példában az aktuális ablakpozíciót látjuk.

Connect(wxEVT_MOVE, wxMoveEventHandler(Move::OnMove));

Itt kapcsolódunk egy wxEVT_MOVE eseménytípushoz az OnMove() metódussal.

wxPoint size = event.GetPosition();

Az esemény paraméter az OnMove() metódusban egy objektum az aktuális eseményhez. Esetünkben ez a wxMoveEvent osztály. Ez az objektum tartalmaz információkat az eseményről. Megkaphatjuk az aktuális kurzorpozíciót az esemény GetPosition() metódusával.

Move event

Figure: Move event

Eseményszaporítás

Kétféle esemény létezik. Az alapesemények és a parancsesemények. A parancsesemények gyermek, szülő és nagyszülő komponensek között is terjednek, egymáshoz eljutnak. Az alapesemények, mint például a wxCloseEvent nem. Ezek nem jutnak el más komponensek felé.

Alapértelmezésként ha egy eseménykezelő elkap egy eseményt, az eseményfigyelés leáll. Az eseményfigyelés újraindítása a Skip() metódus hívásával lehetséges.

propagate.h
#include <wx/wx.h>
 
class Propagate : public wxFrame
{
public:
    Propagate(const wxString& title);
 
    void OnClick(wxCommandEvent& event);
 
};
 
 
class MyPanel : public wxPanel
{
public: 
    MyPanel(wxFrame *frame, int id);
 
    void OnClick(wxCommandEvent& event);
};
 
 
class MyButton : wxButton
{
public:
    MyButton(MyPanel *panel, int id, const wxString &label);
 
    void OnClick(wxCommandEvent& event);
 
};
propagate.cpp
#include <iostream>
#include "propagate.h"
 
const int ID_BUTTON = 1;
 
Propagate::Propagate(const wxString& title)
      : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
    MyPanel *panel = new MyPanel(this, -1);
 
    new MyButton(panel, ID_BUTTON, wxT("Ok"));
 
    Connect(ID_BUTTON, wxEVT_COMMAND_BUTTON_CLICKED, 
        wxCommandEventHandler(Propagate::OnClick));
 
    Centre();
}
 
 
void Propagate::OnClick(wxCommandEvent& event) 
{
    std::cout << "event reached frame class" << std::endl;
    event.Skip();
}
 
 
MyPanel::MyPanel(wxFrame *frame, int id)
      : wxPanel(frame, id)
{
    Connect(ID_BUTTON, wxEVT_COMMAND_BUTTON_CLICKED, 
        wxCommandEventHandler(MyPanel::OnClick));
} 
 
void MyPanel::OnClick(wxCommandEvent& event) 
{
    std::cout << "event reached panel class" << std::endl;
    event.Skip();
}
 
 
MyButton::MyButton(MyPanel *mypanel, int id, const wxString& label)
      : wxButton(mypanel, id, label, wxPoint(15, 15))
{
    Connect(ID_BUTTON, wxEVT_COMMAND_BUTTON_CLICKED, 
        wxCommandEventHandler(MyButton::OnClick));
} 
 
 
void MyButton::OnClick(wxCommandEvent& event) 
{
    std::cout << "event reached button class" << std::endl;
    event.Skip();
}
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
    public:
      virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "propagate.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
 
      Propagate *prop = new Propagate(wxT("Propagate"));
      prop->Show(true);
 
      return true;
}

A példánkban van egy gomb, egy panelon. A panel a frame komponensen van. Minden komponens részére definiálunk egy kezelőt.

event reached button class
event reached panel class
event reached frame class

Ezt kapjuk, amikor kattintunk egy gombra. Az esemény elindul a gombtól a panelhez és a frame-hez. Próbáld meg kihagyni több Skip() metódust és nézd, mi történik.

Vetoing events

Néha szükség lehet egy eseményfeldolgozás leállítására. Erre a célra használjuk a Veto() metódust.

veto.h
#include <wx/wx.h>
 
class Veto : public wxFrame
{
public:
    Veto(const wxString& title);
 
    void OnClose(wxCloseEvent& event);
 
};
veto.cpp
#include "veto.h"
 
 
Veto::Veto(const wxString& title)
      : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
 
    Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(Veto::OnClose));
    Centre();
}
 
void Veto::OnClose(wxCloseEvent& event) 
{
    wxMessageDialog *dial = new wxMessageDialog(NULL,
        wxT("Are you sure to quit?"), wxT("Question"),
        wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
 
    int ret = dial->ShowModal();
    dial->Destroy();
 
    if (ret == wxID_YES) {
        Destroy();
    } else {
        event.Veto();
    }
 
}
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
    public:
      virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "veto.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
 
      Veto *veto = new Veto(wxT("Veto"));
      veto->Show(true);
 
      return true;
}

A példánkban a wxCloseEvent eseményt dolgozzuk fel. Ez az esemény akkor következik be, amikor kattintunk az X gombra címsorban, vagy Alt+F4, vagy a Rendszermenüből a Bezárás menüpontot választjuk. Néhány alkalmazásban szeretnénk megakadályozni az ablak véletlen bezárását. Ehhez a wxEVT_CLOSE_WINDOW eseménytípushoz fogunk kapcsolódni.

wxMessageDialog *dial = new wxMessageDialog(NULL, 
    wxT("Are you sure to quit?"), wxT("Question"),
    wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);

A close esemény bekövetkezésére feldobunk egy üzenetablakot.

if (ret == wxID_YES) {
    Destroy();
} else {
    event.Veto();
}

A visszatérési értéktől függően vagy megsemmisítjük az ablakot, vagy elvetjük az eseményt. Jegyezd meg, hogy az ablak bezárásához a Destroy() metódust kell meghívnunk. A Close() metódus meghívásával befejezhetjük egy végtelen ciklusban.

Window identifiers

Window identifiers are integers that uniquely determine the window identity in the event system. There are three ways to create window id's.

let the system automatically create an id

use standard identifiers

create your own id

Each widget has an id parameter. This is a unique number in the event system. If we work with multiple widgets, we must differantiate among them.

wxButton(parent, -1)
wxButton(parent, wxID_ANY)

If we provide -1 or wxID_ANY for the id parameter, we let the wxWidgets automatically create an id for us. The automatically created id's are always negative, whereas user specified id's must always be positive. We usually use this option when we do not need to change the widget state. For example a static text, that will never be changed during the life of the application. We can still get the id, if we want. There is a method GetId(), which will determine the id for us.

Standard identifiers should be used whenever possible. The identifiers can provide some standard graphics or behaviour on some platforms.

ident.h
include <wx/wx.h>
 
class Ident : public wxFrame
{  
  public:
    Ident(const wxString& title);
 
};
ident.cpp
#include "ident.h"
 
Ident::Ident(const wxString& title)
      : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(200, 150))
{
 
    wxPanel *panel = new wxPanel(this, -1);
 
    wxGridSizer *grid = new wxGridSizer(2, 3);
 
    grid->Add(new wxButton(panel, wxID_CANCEL), 0, wxTOP | wxLEFT, 9);
    grid->Add(new wxButton(panel, wxID_DELETE), 0, wxTOP, 9);
    grid->Add(new wxButton(panel, wxID_SAVE), 0, wxLEFT, 9);
    grid->Add(new wxButton(panel, wxID_EXIT));
    grid->Add(new wxButton(panel, wxID_STOP), 0, wxLEFT, 9);
    grid->Add(new wxButton(panel, wxID_NEW));
 
    panel->SetSizer(grid);
    Centre();
}
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
    public:
      virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "ident.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
 
      Ident *ident = new Ident(wxT("Identifiers"));
      ident->Show(true);
 
      return true;
}

In our example we use standard identifiers on buttons. On linux, the buttons have small icons.

Identifiers

Figure: Identifiers

oktatas/programozas/wxwidgets/wxwidgets_kezikoenyv/esemenyek.1566464853.txt.gz · Utolsó módosítás: 2019/08/22 11:07 szerkesztette: admin