7 / 0 / 1
Регистрация: 09.05.2013
Сообщений: 36
1

wxWidgets не обрабатываются события клавиатуры при пересоздании объекта

13.04.2023, 21:53. Показов 2177. Ответов 7

Author24 — интернет-сервис помощи студентам
Есть класс Screen унаследованный от wxPanel. В классе Wnd, унаследованного от wxFrame, хранится std::shared_ptr<Screen>.
Если создать std::shared_ptr<Screen> в конструкторе Wnd, то все нормально - все нужные события перехватываются и обрабатываются в Screen. Но если пересоздать std::shared_ptr<Screen> в каком либо из обработчиков событий объекта с типом Wnd (например, кликнули в меню), то новый Screen не получает события клавиатуры, хотя события мыши нормально обрабатываются.
Пишу под Ubuntu 20.04, wxWidgets версии 3.2.2.1
Что я делаю не правильно?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.04.2023, 21:53
Ответы с готовыми решениями:

Ошибка вызова функции при нажатии клавиши клавиатуры (WxWidgets)
Имеется приложение на WxWidgets: В коде вызывается одна и та же функция двумя способами: ...

Не обрабатываются события
Здравствуйте. &lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;...

Не обрабатываются события PopupMenu
Здрасьте, проблема ясна по названию темы в чём проблема, кто может мне ответить? ;{-...

Не обрабатываются события мыши в консоли
Препод дал код, который ,как пример, показывает обработку событий мыши. Так вот в аудитории все...

7
7 / 0 / 1
Регистрация: 09.05.2013
Сообщений: 36
14.04.2023, 15:54  [ТС] 2
Попробовал унаследоваться от wxWindow, проблема осталась. Если что вот код Screen.h:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Screen : public /*wxPanel*/wxWindow
{
public:
    Screen(wxWindow* parent);
 
    // AbstractScreen
    virtual void Refresh() override;
    virtual void RefreshRegion(const SRect& region) override;
 
    void OnPaint(wxPaintEvent& wx_event);
    void OnMouseLeftDown(wxMouseEvent& wx_event);
    void OnMouseLeftUp(wxMouseEvent& wx_event);
 
    ...
 
    void OnKeyboardUp(wxKeyEvent& wx_event);
    void OnResize(wxSizeEvent& wx_event);
 
private:
    void PaintBackground(wxBufferedPaintDC& dc);
 
    DECLARE_EVENT_TABLE()
};
Код Screen.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Screen::Screen(wxWindow* parent)
    : wxWindow(parent, wxID_ANY, wxPoint{0, 0}, parent->GetSize())
{
}
 
...
 
BEGIN_EVENT_TABLE(Screen, wxWindow)
    EVT_PAINT(Screen::OnPaint)
    EVT_LEFT_DOWN(Screen::OnMouseLeftDown)
    EVT_LEFT_UP(Screen::OnMouseLeftUp)
    
    ...
 
    EVT_KEY_UP(Screen::OnKeyboardUp)
    EVT_SIZE(Screen::OnResize)
END_EVENT_TABLE()
Если вот так создавать объект Screen в конструкторе:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Wnd : public wxFrame
{
public:
    Wnd(const wxString& title)
        : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(800, 600))
        , screen_(new wx::Screen(this))
    {
          // Даже если раскоментировать код ниже - все будет работать
          // screen_.reset(new wx::Screen(this))
          // screen_.reset(new wx::Screen(this))
          // screen_.reset(new wx::Screen(this))
    }
 
    void OnAbout(wxCommandEvent& event);
    void OnQuit(wxCommandEvent& event);
 
 
private:
    wx::Screen::SPtr screen_;
 
    DECLARE_EVENT_TABLE()
};
Таблица обработчиков событий так же есть и для Wnd:

C++
1
2
3
4
BEGIN_EVENT_TABLE(Wnd, wxFrame)
    EVT_MENU(wxID_ABOUT, Wnd::OnAbout)
    EVT_MENU(wxID_EXIT, Wnd::OnQuit)
END_EVENT_TABLE()
Но если вызвать screen_.reset(new wx::Screen(this)) например в обработчике OnAbout(), то события клавиатуры перестают перехватываться. А события мыши работают
0
6103 / 3459 / 1404
Регистрация: 07.02.2019
Сообщений: 8,780
14.04.2023, 18:58 3
elax, зачем вам понадобился shared_ptr? В wxWidgets, как и во многих подобных фреймворках, семантика управления временем жизни объектов отражает семантику владения - отношения parent-child. Вы только UB привносите, добавлением сюда shared_ptr.

Цитата Сообщение от elax Посмотреть сообщение
wx::Screen::SPtr screen_;
Заменить wx::Screen::SPtr на обычный указатель, а когда нужно пересоздать объект, то в вашем обработчике делаете так:
C++
1
2
screen_->Destroy();
screen_ = new wx::Screen(this);
1
7 / 0 / 1
Регистрация: 09.05.2013
Сообщений: 36
15.04.2023, 12:21  [ТС] 4
zayats80888, большое спасибо! Но ситуация с событиями клавиатуры не исправилась, все так же - мышь работает, клавиатура нет.

Добавлено через 53 минуты
Разобрался. Надо было еще после пересоздания Screen установить в него фокус:
C++
1
screen_->SetFocus();
Добавлено через 9 минут
Открытым вопросом осталось только - почему Screen не устанавливался в фокус... ведь мышкой я в него кликал
0
2443 / 1841 / 406
Регистрация: 15.12.2013
Сообщений: 8,237
16.04.2023, 15:32 5
Цитата Сообщение от elax Посмотреть сообщение
Открытым вопросом осталось только - почему Screen не устанавливался в фокус... ведь мышкой я в него кликал
Предоставьте воспроизводимый пример, чтобы не гадать в чем там дело.
1
7 / 0 / 1
Регистрация: 09.05.2013
Сообщений: 36
17.04.2023, 19:50  [ТС] 6
Вот пример:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "wx/wx.h"
 
class Screen : public wxPanel
{
public:
    Screen(wxWindow* parent)
        : wxPanel(parent, wxID_ANY, wxPoint{0, 0}, parent->GetSize())
    {}
 
    void OnMouseLeftDown(wxMouseEvent& wx_event)
    {
        int a = 0;
        ++a;
    }
 
    void OnMouseLeftUp(wxMouseEvent& wx_event)
    {
        int a = 0;
        ++a;
    }
 
    void OnKeyboardDown(wxKeyEvent& wx_event)
    {
        int a = 0;
        ++a;
    }
 
    void OnKeyboardUp(wxKeyEvent& wx_event)
    {
        int a = 0;
        ++a;
    }
 
    DECLARE_EVENT_TABLE()
};
 
BEGIN_EVENT_TABLE(Screen, wxPanel)
    EVT_LEFT_DOWN(Screen::OnMouseLeftDown)
    EVT_LEFT_UP(Screen::OnMouseLeftUp)
    EVT_KEY_DOWN(Screen::OnKeyboardDown)
    EVT_KEY_UP(Screen::OnKeyboardUp)
END_EVENT_TABLE()
 
class Wnd : public wxFrame
{
public:
    Wnd(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(800, 600))
       , screen_(new Screen(this))
    {
        wxMenu *file_menu = new wxMenu();
        file_menu->Append(wxID_EXIT, wxT("E&xit"), wxT("Exit programm"));
 
        wxMenu *help_menu = new wxMenu();
        help_menu->Append(wxID_ABOUT, wxT("&About"), wxT("Show about dialog"));
 
        wxMenuBar *menu_bar = new wxMenuBar();
        menu_bar->Append(file_menu, wxT("&File"));
        menu_bar->Append(help_menu, wxT("&Help"));
        SetMenuBar(menu_bar);
 
        Centre();
    }
 
    void OnAbout(wxCommandEvent& event)
    {
        int a = 0;
        ++a;
 
        screen_->Destroy();
        screen_ = new Screen(this);
        // Если раскоментировать, то события клавиатуры начинают работать.
        //screen_->SetFocus();
    }
    void OnQuit(wxCommandEvent& event)
    {
        int a = 0;
        ++a;
    }
 
private:
    Screen* screen_;
 
    DECLARE_EVENT_TABLE()
};
 
BEGIN_EVENT_TABLE(Wnd, wxFrame)
    EVT_MENU(wxID_ABOUT, Wnd::OnAbout)
    EVT_MENU(wxID_EXIT, Wnd::OnQuit)
END_EVENT_TABLE()
 
class WxApp : public wxApp
{
public:
    virtual bool OnInit() override
    {
        wxImage::AddHandler(new wxPNGHandler);
 
        Wnd *wnd = new Wnd(wxT("GD Editor"));
        wnd->Show(true);
 
        return true;
    }
};
 
DECLARE_APP(WxApp)
IMPLEMENT_APP(WxApp)
Для проверки:
1. Ставим брекпоинты в обработчики событий класса Screen.
2. Запускаем в отладчике.
3. Кликаем мышкой в окно - события мыши обрабатывается в соответствующем обработчике.
4. Кликаем клавиатурой в окне - события клавиатуры обрабатываются в соответствующем обработчике.
5. Кликаем в меню "Help->About", это заставит пересоздаться Screen.
6. Кликаем мышкой в окно - события мыши обрабатывается в соответствующем обработчике.
7. Кликаем клавиатурой в окне - события клавиатуры больше не обрабатываются.

Если раскоментировать строку "//screen_->SetFocus();" - все начинает работать.
0
6103 / 3459 / 1404
Регистрация: 07.02.2019
Сообщений: 8,780
17.04.2023, 21:02 7
Цитата Сообщение от elax Посмотреть сообщение
Открытым вопросом осталось только - почему Screen не устанавливался в фокус... ведь мышкой я в него кликал
Цитата Сообщение от elax Посмотреть сообщение
6. Кликаем мышкой в окно - события мыши обрабатывается в соответствующем обработчике.
7. Кликаем клавиатурой в окне - события клавиатуры больше не обрабатываются.
Потому что событие клика мышкой вы перехватываете и оно не генерирует событие FocusEvent, а от предыдущих операций фокус остался на меню. Если событие мыши скипнуть, например, то фокус будет передавться по клику мыши:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include "wx/wx.h"
 
class Screen : public wxPanel
{
public:
    Screen(wxWindow* parent)
        : wxPanel(parent, wxID_ANY, wxPoint{0, 0}, parent->GetSize())
    {}
 
 
    void OnMouseLeftDown(wxMouseEvent& wx_event)
    {
        wxLogDebug("%s", __FUNCTION__);
        wx_event.Skip(); //<-------- это просто для демонстрации вышесказанного
/*
        // можно просто устанавливать фокус, если не в фокусе
        if (!this->HasFocus())
        {
            wxLogDebug("Setting focus!");
            this->SetFocus();
        }
*/
    }
 
    void OnMouseLeftUp(wxMouseEvent& wx_event)
    {
        wxLogDebug("%s", __FUNCTION__);
    }
 
    void OnKeyboardDown(wxKeyEvent& wx_event)
    {
        wxLogDebug("%s", __FUNCTION__);
    }
 
    void OnKeyboardUp(wxKeyEvent& wx_event)
    {
        wxLogDebug("%s", __FUNCTION__);
    }
 
    DECLARE_EVENT_TABLE()
};
 
BEGIN_EVENT_TABLE(Screen, wxPanel)
    EVT_LEFT_DOWN(Screen::OnMouseLeftDown)
    EVT_LEFT_UP(Screen::OnMouseLeftUp)
    EVT_KEY_DOWN(Screen::OnKeyboardDown)
    EVT_KEY_UP(Screen::OnKeyboardUp)
END_EVENT_TABLE()
 
class Wnd : public wxFrame
{
public:
    Wnd(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(800, 600))
       , screen_(new Screen(this))
    {
        wxMenu *file_menu = new wxMenu();
        file_menu->Append(wxID_EXIT, wxT("E&xit"), wxT("Exit programm"));
 
        wxMenu *help_menu = new wxMenu();
        help_menu->Append(wxID_ABOUT, wxT("&About"), wxT("Show about dialog"));
 
        wxMenuBar *menu_bar = new wxMenuBar();
        menu_bar->Append(file_menu, wxT("&File"));
        menu_bar->Append(help_menu, wxT("&Help"));
        SetMenuBar(menu_bar);
 
        Centre();
    }
 
    void OnAbout(wxCommandEvent& event)
    {
        wxLogDebug("%s", __FUNCTION__);
 
        screen_->Destroy();
        screen_ = new Screen(this);
        // Если раскоментировать, то события клавиатуры начинают работать.
        //screen_->SetFocus();
    }
    void OnQuit(wxCommandEvent& event)
    {
        wxLogDebug("%s", __FUNCTION__);
    }
 
private:
    Screen* screen_;
 
    DECLARE_EVENT_TABLE()
};
 
BEGIN_EVENT_TABLE(Wnd, wxFrame)
    EVT_MENU(wxID_ABOUT, Wnd::OnAbout)
    EVT_MENU(wxID_EXIT, Wnd::OnQuit)
END_EVENT_TABLE()
 
class WxApp : public wxApp
{
public:
    virtual bool OnInit() override
    {
        wxImage::AddHandler(new wxPNGHandler);
 
        Wnd *wnd = new Wnd(wxT("GD Editor"));
        wnd->Show(true);
 
        return true;
    }
};
 
DECLARE_APP(WxApp)
IMPLEMENT_APP(WxApp)
2
7 / 0 / 1
Регистрация: 09.05.2013
Сообщений: 36
17.04.2023, 22:56  [ТС] 8
zayats80888 Большое спасибо за пояснение!!!
0
17.04.2023, 22:56
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.04.2023, 22:56
Помогаю со студенческими работами здесь

Анимация NavigationView - не обрабатываются события от кнопок
Решил опробовать данное решение.https://github.com/mxn21/FlowingDrawer. Проблема никак не могу...

Не обрабатываются события в динамически добавленых строках таблицы
Добрый день! Мне на странице надо иметь возможность динамически добавить строчки в таблицу (в...

События мыши rightclick и mouseClick обрабатываются вместе
на форме висит contextmenustrip и на иконку в трее повешены еще mouseClick mouseDoubleClick ...

Не обрабатываются события мыши. WPF не заходит в них
Создаю в WPF UserControl, который динамически создает canvas и в нем отрисовывает прямоугольник. В...

Перехват события в wxWidgets
Добрый день. делаю класс MyPlane наследник от wxPanel. На панели размещаю два контрола...

Падение при пересоздании текстуры
Как правильно пересоздать текстуру с увеличением её размера? Например, я сначала создаю текстуру...

Handler при пересоздании активити
У меня есть поток Thread, который запускается во фрагменте и получает ссылку на изображение с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru