инициализация контроллов (wx c++ vs2017

Это русская секция форума wxWidjets. В этой секции вы можете обсуждать любые вопросы, связанные с wxWidgets на вашем родном языке.
genx74
Earned a small fee
Earned a small fee
Posts: 19
Joined: Sat Feb 11, 2023 6:14 am

Re: инициализация контроллов (wx c++ vs2017

Post by genx74 »

Yes Yes Yes. Thank you very much for your help and patience! You answered me before I had time to ask)) I just had an idea to take the font size as the basis for scaling. Which the user can change in the settings, or which is automatically calculated based on the screen resolution when the program starts. I just wanted to ask "whether the best element size is taken based on its content?".

I'm just studying sequentially the book "Julian Smart and Kevin Hock
with Stefan Csomor". And there I saw that you can create elements and at the end of the constructor apply something like "set size based on content". And the content is created with the "best size" based on the given font size. And I already saw that in wx it is very convenient to work with the font.You can even ignore the OS Windos style set by the user, but simply extract this font, increase its size, and install it.This will be the initial size of the window with the correct height and width, and not, as I indicated, just visually by eye (200, 400) and all elements shrink to this size at random and not according to the "best size" rule.In the coming days I will experiment.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: инициализация контроллов (wx c++ vs2017

Post by ONEEYEMAN »

Hi,
In order to do an automatic HighDPI scaling, you have to have a Manifest with HighDPIAware setting.
Otherwise , you are correct.

Thank you.
genx74
Earned a small fee
Earned a small fee
Posts: 19
Joined: Sat Feb 11, 2023 6:14 am

Re: инициализация контроллов (wx c++ vs2017

Post by genx74 »

Hello.
I figured out the sizers, while everything turns out, it works, it scales depending on the font. wxwidget has an enumerator and 7 font sizes, which is enough.
I can't figure out the veto() function. I have a spinbutton and a button with an image. On the spinup spindown event, certain settings are loaded into the dialog box, incl. button card. The settings are taken from the vector containing the structures. The user can select an image with a click button, then press the spinbutton to go to the next page. But if the picture is not selected - button bitmap = wxNULLbitmap then you need to disable the spinup spindown event. I looked at an example using veto(). But it is applied inside the event, i.e. when the spinvalue has already changed.

spinvalue is used to get the element of the vector. those. vector[spinvalue]. Therefore, if an event occurs when it should not be, the numbering is lost. You can probably roll back the setvalue (getvalue -1) value in this case, or do bind-unbind, connect-disconnect, but I think it would be more correct to use veto on the spinbutton, but not in the spinup spindown event itself, but somewhere in the picture selection event. If at button.click the picture is not selected, it remains empty, then disable the spinup spindown event. Could you please advise, because all the examples only consider veto on close in the close or quit event itself.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: инициализация контроллов (wx c++ vs2017

Post by ONEEYEMAN »

Hi,
In this case you need to disable the control, so the user will not be able to change the spin value.
Or depending on the application design/needs, hide/show the spin control.

Thank you.
genx74
Earned a small fee
Earned a small fee
Posts: 19
Joined: Sat Feb 11, 2023 6:14 am

Re: инициализация контроллов (wx c++ vs2017

Post by genx74 »

Well, yes, that's what I'm trying to do with event.veto() However, I access this event inside the event when the spinvalue change has already happened. How to use veto for spinup event from another event like button click?
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: инициализация контроллов (wx c++ vs2017

Post by ONEEYEMAN »

Hi,
Can you describe in English or Russian the flow control of the program you are doing?

What I suggested is to call spinctrl->Disable() so that user will not be able to do anything with the control.

Thank you
genx74
Earned a small fee
Earned a small fee
Posts: 19
Joined: Sat Feb 11, 2023 6:14 am

Re: инициализация контроллов (wx c++ vs2017

Post by genx74 »

Спасибо за помощь. Я попробую использовать disable(). Я все еще пишу прототип программы, чтобы изучить wxwidget и найти нужные мне методы и свойства и научиться их использовать. Грубо говоря, часть программы, над которой я сейчас работаю, выглядит так:

Есть wxPanel, в ней есть несколько wxCtrlText, wxButton с картинкой и spinbutton. Есть структура, в которой хранятся значения wxCtrlText и путь к картинке. Есть вектор этих структур. С помощью wxButton.click() вызывается диалоговое окно выбора изображения. Если - ок, картинка устанавливается как bitmap для wxButton. Пользователь может заполнить wxCtrlText данными и нажать spinup. В этом случае данные из элементов управления копируются в структуру, а структура добавляется в вектор vector.push_back(mystruct). Если пользователь нажимает кнопку Spindown, то загружаются данные из предыдущей структуры, сохраненной в векторе. В этом случае, какой элемент вектора необходимо загрузить, определяется значением spinvalue.

Я думал, какой признак должен определять, заполнены данные или нет, и я думал, что если нет картинки, то нет и данных. Таким образом, если пользователь нажал кнопку, но выбрал «отменить», растровое изображение на кнопке устанавливается в wxNULLbitmap; refresh(); кнопка пуста. И тогда при нажатии spinup значение спина не должно меняться, иначе значение не будет совпадать с порядковым номером элемента в векторе.

Если картинка выбрана и пользователь нажимает spinup, то данные сохраняются в vector[spinvalue] затем, если spinvalue < vector.size (то есть в векторе есть следующий элемент), то данные и картинка сохраняются в вектор vector[spinvalue]. Если spinvalue = vector.size (текущий элемент вектора — последний), то текущие данные также сохраняются и в вектор добавляется новая структура. Чтобы избежать пустых структур в векторе, пользователь не может перемещаться вперед или назад, если изображение не выбрано. Только если текущие данные являются последним элементом вектора, когда spindown и картинки нет, считается, что пользователь передумал добавлять новую запись, поэтому в этом случае обратный переход разрешен и vector.pop_back(spinvalue) выполняется, тое удаляется последний элемент вектора.

Это немного похоже на работу такого элемента как Tab с winapi, но в VBA такого элемента не было, поэтому реализация этой части программы была такой, как я описал. Только там обработка данных была не в самих событиях spinup spindown, а в этих событиях проверялось изображение и только потом вызывалась соответствующие функции передачи данных.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: инициализация контроллов (wx c++ vs2017

Post by ONEEYEMAN »

Доброго времени суток,
Я понял.
Самое простое решение - вызвать Disable() для спина и вызывать Enable() только если есть картинка.
Кстати, нажатие на саму кнопку - не лучшее решение.
Попробуйте справа от кнопки положить wxFilePicker.

Как-то так.

Спасибо.
genx74
Earned a small fee
Earned a small fee
Posts: 19
Joined: Sat Feb 11, 2023 6:14 am

Re: инициализация контроллов (wx c++ vs2017

Post by genx74 »

Спасибо.
Да, disable() это хорошее решение проблемы

Да, click надо будет переделать, потому что файловый диалог загружается относительно долго, во время этого сохраняется нажатое состояние кнопки, поэтому изображение пропадает потом появляется через пару секунд. Это некрасиво и неправильно, единственное почему я использую кнопку для изображения, потому что не знал как прикрутить событие click() к staticbitmap. Недавно я увидел в примере как это сделать и хочу попробовать.
Отдельную кнопку не хотелось бы добавлять для выбора файла из экономии места. Ну и както вроде логично, кликнул картинку и сразу выбрал, тем более в диалоге сразу можно и папку по умолчанию нужную прописать и фильтр форматов настроить.
К сожалению в учебниках описаны только основные виджеты. И вот разные полезные виджеты иногда попадаются в комментариях на форумах, когда часть кода где их можно было бы использовать уже написана.

И еще пока одну проблему не могу победить. В классе wxPanel прописаны все контролы и в конце конструктора вызывается загрузка первой картинки. Т.е. при создании этого диалога, по умолчанию загружается какой то шаблон\образец данных. Размер картинки не устанавливается, потому что объект только создается и не имеет наверное еще свойств size (я так думаю). В процессе работы когда окно показано, то для загружаемой картинки делается rescale под размер кнопки в которую она загружается. А вот в самом конструкторе класса это не работает. Хотя в конструкторе в конце стоит layout() и только потом загрузка первой картинки.
wxPanel создается по нажатию меню в mainframe. я думал в mainframe после создания объекта wxPanel вызвать функцию устанавливающую первые данные по умолчанию, и тогда картинка бы правильно была rescale потому что окно есть и показано в нужном масштабе. Однако в mainframe мне не виден метод wxPanel.setfirstdata(); хотя он в классе wxPanel как public.

И в wxwidget странно реализован метод show, т.е. я могу только enable\disable элементы в зависимости нужны они при текущих настройках или не нужны. Если же я пытаюсь использовать show\hide то они не уничтожаются но из сайзеров исчезают и все расположение контролов сбивается. непонятно почему ведь кнопки\объекты не уничтожаются а просто становятся show(false)
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: инициализация контроллов (wx c++ vs2017

Post by ONEEYEMAN »

Доброго времени суток,
genx74 wrote: Sun Mar 19, 2023 5:41 pm Спасибо.
Да, disable() это хорошее решение проблемы

Да, click надо будет переделать, потому что файловый диалог загружается относительно долго, во время этого сохраняется нажатое состояние кнопки, поэтому изображение пропадает потом появляется через пару секунд. Это некрасиво и неправильно, единственное почему я использую кнопку для изображения, потому что не знал как прикрутить событие click() к staticbitmap. Недавно я увидел в примере как это сделать и хочу попробовать.
Отдельную кнопку не хотелось бы добавлять для выбора файла из экономии места. Ну и както вроде логично, кликнул картинку и сразу выбрал, тем более в диалоге сразу можно и папку по умолчанию нужную прописать и фильтр форматов настроить.
wxFilePicker даст Вам возможность выбрать файл и сделать все о чем Вы здесь написали. Вам не нужно изобретать велосипед и писать диалог самому.
И еще - это как файл выбипается . В 99% всех приложений используется FilePicker. Пользователь просто булет смотреть и не понимать что ему делать.
genx74 wrote: Sun Mar 19, 2023 5:41 pm К сожалению в учебниках описаны только основные виджеты. И вот разные полезные виджеты иногда попадаются в комментариях на форумах, когда часть кода где их можно было бы использовать уже написана.

И еще пока одну проблему не могу победить. В классе wxPanel прописаны все контролы и в конце конструктора вызывается загрузка первой картинки. Т.е. при создании этого диалога, по умолчанию загружается какой то шаблон\образец данных. Размер картинки не устанавливается, потому что объект только создается и не имеет наверное еще свойств size (я так думаю). В процессе работы когда окно показано, то для загружаемой картинки делается rescale под размер кнопки в которую она загружается. А вот в самом конструкторе класса это не работает. Хотя в конструкторе в конце стоит layout() и только потом загрузка первой картинки.
wxPanel создается по нажатию меню в mainframe. я думал в mainframe после создания объекта wxPanel вызвать функцию устанавливающую первые данные по умолчанию, и тогда картинка бы правильно была rescale потому что окно есть и показано в нужном масштабе. Однако в mainframe мне не виден метод wxPanel.setfirstdata(); хотя он в классе wxPanel как public.
Можно посмотреть на код и скрееншот?
genx74 wrote: Sun Mar 19, 2023 5:41 pm И в wxwidget странно реализован метод show, т.е. я могу только enable\disable элементы в зависимости нужны они при текущих настройках или не нужны. Если же я пытаюсь использовать show\hide то они не уничтожаются но из сайзеров исчезают и все расположение контролов сбивается. непонятно почему ведь кнопки\объекты не уничтожаются а просто становятся show(false)
There is a solution for that - use wxRESERVE_SPACE_EVEN_IF_HIDDEN when adding the control to the sizer.

Thank you.
genx74
Earned a small fee
Earned a small fee
Posts: 19
Joined: Sat Feb 11, 2023 6:14 am

Re: инициализация контроллов (wx c++ vs2017

Post by genx74 »

Привет! Что-то я запутался с классами.
Есть класс mainframe::public wxFrame
в этом классе есть
public:
std::vector <int> v1;
в определенном событии создается экземпляр другого класса class dialog:: public wxdialog
который в конструкторе принимает родительское окно wxWindow* parent согласно объявлению wxdialog

класс dialog управляет своими контролами, загружает картинки, устанавливает тултипы, принимает данные. т.е. его задача взять данные от пользователя. но эти данные будут использоваться в других функциях, других классах.

я не могу получить доступ к вектору в классе mainframe из класса dialog
потому что paren приходит как wxWindows а не как mainframe

в классе dialog в одном из методов я попробовал через динамическое преобразование int size = wxDynamicCast(this->GetParent(), MainFrame)->v1.size();
вроде работает, но не удобно. каждый раз при добавлении\удалении элемента вектора, либо при получении\сохранении значения использовать динамическое преобразование

я также думал в конструкторе класса один раз сделать ссылку типа mainframe* parent_frame = wxDynamicCast(this->GetParent(), MainFrame);
чтобы затем использовать в классе dialog без динамического преобразования. но это не работает.

в классе mainframe создаются разные экземпляры классов подобных dialog :: public wxdialog
у каждого класса свои функции и задачи, каждый из них после уничтожения диалога должен сохранять данные в своих векторах.
и далее по различным событиям класса mainframe (из меню или из панелей с кнопками) идет обработка этих данных.

Можно было конечно сделать все векторы с данными пабликами, вообще вне класса mainframe, потому что в любом классе всегда создается только один экземпляр и путаницы между объектами не возникнет, но это крайний вариант

Попробовал также объявить в mainframe friend class dialog; но в классе диалог интелисенс всё равно пишет что нет доступа, нужно указывать конкретный экземпляр класса для обращения к его элементам.

Подскажите пожалуйста.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: инициализация контроллов (wx c++ vs2017

Post by ONEEYEMAN »

Dobrogo vremeni sutok,

Code: Select all

class MyDialog : public wxDialog
{
public:
    MyDialog(...);
    int GetA() const { return a; }
private:
    int a;
};

void MyFrame::InvokeDialog(...)
{
    MyDialog dlg(...);
    res = dlg.ShowModal();
    if( res == wxID_OK )
    {
        v.push_back( dlg.GetA() );
    }
}
Vse prosto i dostatiochno krasivo... ;-)

Spasibo.
genx74
Earned a small fee
Earned a small fee
Posts: 19
Joined: Sat Feb 11, 2023 6:14 am

Re: инициализация контроллов (wx c++ vs2017

Post by genx74 »

Привет. Нет это не так.

Должно быть примерно так:

class MyFrame : public wxFrame
{
MyFrame(...);
public:
std::vector <int> v1;
std::vector <int> v2;
std::vector <int> v3;

//--------------------------------------
здесь будут функции которые работают используя данные в векторах, например функция рисует график, функция формирует отчет.
}

void MyFrame::InvokeDialog(...)
{
MyDialog dlg(...);
dlg.ShowModal();
dlg.Destroy();
}


class MyDialog1 : public wxDialog(wxWindow* parent).....;
{
public:
MyDialog1(...);
void getdata(int item); данные берутся из вектора в форму v1
void savedata(int item); данные сохраняются из формы в вектор v1

так вот здесь parent->v1[1] = 5 не работает
и int x = parent->v1[2]; не работает, потому что parent приходит как wxWindow а не MyFrame

};

class MyDialog2 : public wxDialog(wxWindow* parent.....)
{
public:
MyDialog2(...);
void getdata(int item); данные берутся из вектора в форму v2
void savedata(int item); данные сохраняются из формы в вектор v2

так вот здесь parent->v2[1] = 5 не работает
и int x = parent->v2[2]; не работает, потому что parent приходит как wxWindow а не MyFrame
};
Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 357
Joined: Tue Jun 07, 2016 1:07 pm

Re: инициализация контроллов (wx c++ vs2017

Post by Kvaz1r »

Похоже на проблему с проектированием, но если переделывать не хочется, оберните свой вектор в wxSharedPtr и передавайте его в диалог отдельно, где и будете использовать. Тогда и кастовать при вызовах не придется, решение грязное, но рабочее :D
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: инициализация контроллов (wx c++ vs2017

Post by ONEEYEMAN »

Доброго времени суток,
genx74 wrote: Sat Apr 29, 2023 6:50 am Привет. Нет это не так.
Почему не так. Все так. Давайте по пунктам///
genx74 wrote: Sat Apr 29, 2023 6:50 am Должно быть примерно так:

Code: Select all

class MyFrame : public wxFrame
{
       MyFrame(...);
public:
     std::vector <int> v1;
     std::vector <int> v2;
     std::vector <int> v3;

     //--------------------------------------
     здесь будут функции которые работают используя данные в векторах, например функция рисует график, функция формирует отчет.
}
Согласен.
genx74 wrote: Sat Apr 29, 2023 6:50 am

Code: Select all

void MyFrame::InvokeDialog(...)
{
    MyDialog dlg(...);
    dlg.ShowModal();
    dlg.Destroy();
}
Не согласен.
Вопрос первый - для чего вызывается "dlg.Destroy();"
Диалог модальный и создан на стеке а значит самоуничтожится.
Далее:
Функция "ShowModal();" возвпазает значение. На основании этого значения я в моем коде забираю данные из диалога. Новые данные которые пользователь (или программа) ввела в ветор.
Не вижу проблемы в своем коде а Ваш код работать не будет/ А если диалог(и) находятся в вами созданной библиотеке которая не должна зависеть от основного приложения - то там вообще паботать будет только мой код.
genx74 wrote: Sat Apr 29, 2023 6:50 am

Code: Select all

class MyDialog1 : public wxDialog(wxWindow* parent).....;
{
public:
    MyDialog1(...);
    void getdata(int item); данные берутся из вектора в форму   v1
    void savedata(int item); данные сохраняются из формы в вектор     v1

так вот здесь parent->v1[1] = 5 не работает
и int x  = parent->v1[2]; не работает, потому что parent приходит как  wxWindow а не MyFrame

};
Конечно не работает и не будет и не ДОЛЖНО работать.
Диалог должен знать только одно - у него есть родитель. Какой тип родителя ему по барабану.

Вот такой код будет работать:

Code: Select all

void MyFrame::InvokeDialog(...)
{
    MyDialog dlg(...);
    int res = dlg.ShowModal();
    if( res == wxID_OK )
        v1 = dlg.GetData();
}

class MyDialog1 : public wxDialog(.....)
{
public:
    MyDialog1(wxWindow *parent, const std::vector &param);
// Ваши данные из вектора будут сохранены в дилоне в его констпукторе.
// Соответственно остается только одна функция
    std::vector &getdata() const; данные сохраняются из формы в вектор     v1
private:
    std::vector<int> dialogData;
};
Мне кажется я знаю почему Вы так не хотите.
Подозреваю Вы не хотите держать два вектора - один в диалоге, один в главном окне.
Увы однако без этого никуда не деться.
С точки зрения С++ и простой логики мое рещение верное.

Если оно нк работает - отпишитесь что конкреино не работает и детально объясните как Вы его тестировали.

Позвольте сапрсить - Вы на каком железе пишете и тестируете? Сколько оперативки?

Если у Вас железо с онраничениями в ОЗУ - забудьте про wxWidgets.

Спасибо.

Или можно использовать решение предложенное Kvazir, но как он написал - это hack и значит должен быть аккуратно задокуметирован и оттестирован. ;-)
Post Reply