C/C ++ UI elementlarini funksiyalarga ulashning moslashuvchan va tezkor usuli

Hozir men o'yinning UI funksiyasida ishlayapman, bu juda kam GUI dizayniga ega bo'ladi, ammo u funktsional va moslashuvchan bo'lishi kerak, masalan. qayta ishlashga oson.

Quadlardan ixtiyoriy to'qimalarga va rangga ega bo'lgan barcha GUI elementlarni (tugmalar, skanerlar, tugmachalar, katakchalar) qurishni rejalashtirmoqdamiz. Ushbu quadlar matn va sichqonchani bosishni aniqlash uchun chegara vazifasini bajaradi.

Lekin tugmalar kabi tetikleyiciler uchun haqiqiy vazifani bog'lashning samarali usulini topish qiyinchilik tug'dirmoqda. Men shu kabi tugmani belgilashni o'ylardim:

struct Button{
    unsigned int quadIndex; //an index into the array of quads, which themselves store indices into arrays of positions and sizes
    void (*func)(int); //a pointer to the function to be called when this button is being interacted with. the parameter of the function will be the state of the relevant mouse button
}

Lekin bu bilan men faqat tugmachani chaqirishga imkon beradigan kodni void func (int) funktsiyasidan foydalanib, har bir tugma vazifasini bajarish uchun meni tez-tez saralash funktsiyasini yozishga majbur qiladi. Har kim shunday qiladimi, yoki yaxshiroqmi, moslashuvchanmi?

Tahrirlash: Ishlash/yuqori javob berish men uchun juda muhim ekan, men ko'rsatgichlardan, virtual funktsiyalardan va boshlang'ich sinflardan qochmoqchiman. Funktsional va moslashuvchan yechim uchun o'ynash kerak bo'lgan minimal ma'lumotlarga e'tibor qaratadigan shaffof, aniq yechim qidiraman

0
Mening fikrimcha, Ian Young, sekin urish sizning o'yiningizdagi javobsizligining buzilishi emas. Harakat qilish uchun harakatga kirish uchun bir nechta qatnov qatlamlari orqali sho'ng'ishimiz kerak bo'lsa ham, biz faqat bitta sekin urishimiz kerak. Har bir kvadratchadan yuzlab, millionlab marta yopiq loopda bajaradigan kod emas. Bu biz "takrorlanadigan" kodni takrorlaymizki, bu kusturmalardan, kechikishlar va chiziqli tomchilardan qochish uchun ishlashga qaratiladi. juda noto'g'ri ish qilmaguningizcha, sekin urish moslamasi o'zi ishlashning mazmunli samarasini bermaydi.
qo'shib qo'ydi muallif DMGregory, manba
Ko'rsatkichlar va virtual funktsiyalar UI elementlari holatida ishlashga sezilarli ta'sir ko'rsatmaydi. Siz o'qilishi mumkin bo'lgan, sozlanadigan va qaytadan foydalanishga yaroqli narsalar yaratishingiz kerak va optimallashtirish ishlarini yanada kengroq kodlash bazasida boshqa CPU/xotira intensiv amaliyotlariga qaratasiz.
qo'shib qo'ydi muallif Ian Young, manba
@DMGregory Ha, men aynan shu narsaga erishaman. Bo'g'inlarni aniqlash, fizika va h.k. kabi narsalar optimallashtirish uchun juda yaxshi nomzodlar.
qo'shib qo'ydi muallif Ian Young, manba
Menimcha, foydalanuvchi interfeysining o'zaro aloqasi yuqori darajada optimallashtirilgan bo'lishi kerak, chunki u foydalanuvchining dasturga bevosita aloqasi bo'lib, dasturni "his qilish" ni o'rnatadi. Suyuq dastur bosqichida ob'ektga yo'naltirilgan yondoshuv etarli bo'lishi mumkin bo'lsa-da, ayniqsa yoqimli o'yin-kulgiga ega bo'lgan yuqori darajali foydalanuvchi/dastur ta'sirida tez-tez uchraydigan yoqimsiz joylar paydo bo'lishi mumkin. Albatta, bu bir nechta pointerning kirish stollari ko'rinadigan ish faoliyatini sezilarli darajada ko'rsatishi uchun hech qanday dalilim yo'q, lekin endi allaqachon menda mavjud bo'lib, faqat ideal echimni topishni xohlayman.
qo'shib qo'ydi muallif Victor, manba

6 javoblar

Birinchidan, tugmani bosishning sezgirligi tufayli ko'rsatgichlardan va virtual funktsiyalardan qochish sizning qismingiz juda ko'p xatolarga yo'l qo'ydi - tinglamaslik kerak bo'lgan odamni tingladingiz. Agar ishlash uchun ko'rsatgichlarni muhokama qilsak, biz nanoseniyalar haqida gaplashyapmiz ( 65 nsning eng yomoni, bitta manbaga ko'ra ) , va agar tugmachani tezroq javob berishni xohlasangiz, javob berishni ko'rsating, sizning xohlaganingizdagina sarflash uchun ushbu nanosaniyadan 100'000'000 sonigacha ega bo'lasiz.

Ya'ni, siz virtual funktsiyalarga qaraysiz (ehtimol std :: unique_ptr ), std : function yoki eski boost :: function . Bularning barchasi sizni saqlashga imkon beradi  har qanday qo'shimcha dalillar va shuningdek ruxsat berish resurslarini umrbod boshqaruvini halokatchi tomonidan to'g'rilash. To'g'ri amalga oshirilgan bo'lsa, std :: function bilan lambdas o'qilishi uchun eng yaxshi kod bo'lishi kerak, lekin virtual funktsiyalarga ega dasturni tuzatish osonroq bo'ladi.

2
qo'shib qo'ydi
Bu erda odamlarning ko'pchiligi nimani anglatadi, tugma işleyicisinin kodi, işleyicinin o'zi murakkabligining bir qismi (nanosaniyeler va yuzlar nanosaniyelerdir). Kodni optimallashtirish har doim juda yaxshi, lekin agar kod faqat nanosaniyani boshlashni boshlasa, daromadlar ahamiyatsiz bo'ladi. Buni o'ylab ko'ring: siz qo'lda ishlaydigan juftlarni (masalan, 3 ns) va ishlovchilarning o'zlarini (masalan, 300 ns) optimallashtirish qilyapsiz. Yaxshisi, estrodiol jarayonni 1% ga oshirasiz (1 ns + 300 ns). Optimallashtirilgan echimlarni izlashga bo'lgan munosabatingiz ajoyib, lekin men optimallashning qayerda foydalandigiga e'tibor beraman.
qo'shib qo'ydi muallif Fleshgrinder, manba
@stimulate Sizga foydalanuvchi kliklarini keshlashni kamaytirishga harakat qilayotganingizni tushunaman. Ya'ni siz nanosaniyani 100 ms davomida bajarish kerak bo'lgan operatsiyani optimallashtirishga harakat qilmoqdasiz. Hatto nima uchun bu aslida ishlamaydi, deb o'ylaganim yo'q, chunki ishlayotgan bo'lsa ham, tezlik 100% ga to'g'ri kelmaydi
qo'shib qo'ydi muallif George, manba
Yo'q, bu nanosaniyalar qo'shilmaydi. Har 100 milodiy ichida bir nechta tugmachani bosib bo'lmaydi. Men sizning javobingiz haqida ikkinchi xatboshida nima qilish mumkinligini aytdim. Men ular bilan aloqasi bo'lmaganligi sababli, men ularga aloqador bo'lmagan ma'lumotlarni kiritmayapman, siz hozircha sizni chalg'itmoqdasiz. Aloqasiz tafsilotlar haqida gapirish, bu shovqini olib tashlamaydi.
qo'shib qo'ydi muallif George, manba
Xush kelibsiz. Menga tavsiyalar tugmachalarga xos edi. interfaol UI elementlari. Boshqa narsalar uchun, ayniqsa, bir xil kod bilan takrorlanadigan ma'lumotlar, ketma-ket va kritik yo'lda (masalan, zarracha effektlari), keshning joylashganligi e'tiborga olinadigan narsadir. UI bilan bog'liq narsalarni ishlatish oson, oson o'zgarishi kerak va ishlash tezligi sizning tezkorligingizda (odatda <100 ms va ayrim maxsus holatlarda <10 milodiy, bir necha keshni kattaroq o'lchamdagi buyurtmalar).
qo'shib qo'ydi muallif George, manba
@JellevanCampen Adolatli bo'lish uchun, keshni sog'inmaguncha - OP qanday tashvishlanadigan narsa - osongina 100 ns ga yetishi mumkin stackoverflow.com/a/29188516/1612743 Lekin bu 0.0001 millisekundga tugma işleyicisinin jami vaqtini emas, balki, foydalanuvchi geribildirimini ta'minlash uchun mavjud bo'lgan vaqtga (100 milodiy) qarash kerak va CPU vaqtiga ko'ra, Joriy ramka (15 milodiy). Sizning fikringiz qoladi, bu faqatgina o'zgartiradigan raqamlar.
qo'shib qo'ydi muallif George, manba
Odatda markerni ishlatishdan qochmoqchiman, chunki new dan foydalanishni xohlamayman. new bilan tuzilgan misollarga ishora qiluvchi ko'rsatgichlar har doim CPU to'xtab qolishiga sabab bo'lgan tasodifiy xotiraga (RAM) kirishlari kerak (agar talab qilingan kesh kesh satrida bo'lsa). Bu men o'qiganim va shuning uchun hamma nusxalarni to'g'ridan-to'g'ri massivlarda saqlayman. Ushbu holatlarni ko'rib chiqsam, ularning barchasini bir marta yechib olaman yoki ko'rsatkichlar orqali indekslardan foydalanaman. Bu, albatta, markerlar bilan (mahalliy xotiraga) ham amalga oshirilishi mumkin, biroq keyinchalik indekslash seriallari mahalliy xotiraga oid ko'rsatgichlar bilan bir xil bo'ladi.
qo'shib qo'ydi muallif Victor, manba
Ushbu nanosaniyalar qo'shiladi. Faqatgina tugmachalarga qaraganda, bitta freymda qayta ishlanishi kerak. Men imkon qadar ko'proq vaqtni ishlatmoqchiman va men oddiygina dasturlash uslubini qidiraman. Men sizdan ko'ra ko'proq tajribaga ega bo'lganingizni hurmat qilaman, lekin "Uni qandaydir qimmatga keltirmaslik, hatto buni qanday qilish mumkinligini aytmayman" degani meni ishontirmaydi.
qo'shib qo'ydi muallif Victor, manba
Bu tugma faqat namuna. Mening dasturim shoshilinch tezkor o'yin bo'lib qoladi, shuning uchun ko'plab tugmachalarni, tugmani bosishni va vaziyatni osongina o'zgartirishga to'g'ri keladi. Ehtimol, men biroz tashvishlanaman, lekin faqat bu narsani to'g'ri qilishga harakat qilaman. Std :: funktsiyasini ko'rib chiqamiz va taqdim etilgan echimlardan bir nechtasini sinab ko'ring. Sizning javobingiz uchun rahmat
qo'shib qo'ydi muallif Victor, manba

Qaysi C ++ standartiga qarshi yozmoqdasiz? C ++ 11 Lambdasni qo'llab-quvvatladi, ular asosan nomlarsiz funktsiyalardir.

Shunday qilib siz o'zingizning funktsiyangiz o'rniga Lambdani belgilashingiz va u erda qo'ng'iroq qilishni istagan barcha funktsiyalarni yozishingiz mumkin. Siz hali ham funktsiya adapterlarini yaratmoqdasiz, lekin ularni onlayn ravishda yozishingiz mumkin, chunki u juda kichikroq:

myButton.func = [someExternalVariable](int idx){ doMagic( buttons[idx], someExternalVariable, 42 ); };
2
qo'shib qo'ydi

Siz shablonlarni ishlatishingiz va funktsiya turini interfeys ostida yashirishingiz mumkin:

class ICallback
{
public:
    virtual void Execute() = 0;
protected:
private:
}

template  ButtonCallback : public ICallback
{
public:
    ButtonCallback(T c_) : c(c_) {}

    void Execute() override
    {
        c();
    }
protected:
private:
    const T c;
}

class Button
{
public:
    Button() 
    {
        clickCallback = new ButtonCallback(/* any function pointer/std::function here. */);
    }
private:
    ICallback* clickCallback;
}

Qo'ng'iroqlar uchun barcha parametrlarga ega ICallback bo'lishi kerak, bu sizning orangizdagi qayta qo'ng'iroqlar bilan siz istagan har qanday interfeysni "ikki barobar" qilish kerak.

1
qo'shib qo'ydi

Create a ButtonBehaviour abstract class with a virtual execute(Button& b)

Keyin tugmani bir necha xatti-harakatlari bo'lishi mumkin:

class Button
{
public:
    void parseMouse(Mouse& m){
        if(isInside(m.pos)) {
            if(m.clicked) {
              m_on_click->execute(*this);
            }
            else {
                if (!m_mouse_inside) {
                    m_mouse_inside = true;
                    m_mouse_enter->execute(*this);
                }
            }
            else {
                if (m_mouse_inside) {
                   m_mouse_inside = false;
                   m_mouse_leave->execute(*this);
                }
            }
        }

    }
private:
    ButtonBehaviour* m_on_mouse_enter;
    ButtonBehaviour* m_on_mouse_leave;
    ButtonBehaviour* m_on_click;
    bool m_mouseinside;
};

Keyinchalik sichqoncha sichqonchaning holatiga qarab mos keladiganlarni chaqiradi.

Shunday qilib, ButtonBehaviour aniq sinflar siz xohlagan narsani qila oladi: boshqa, tugmachalar vazifalarini chaqirish yoki to'g'ridan-to'g'ri kodingizdagi boshqa modullar bilan ishlash.

1
qo'shib qo'ydi
Bu nafaqat qulay foydalanish haqida emas. Bundan tashqari, qayta foydalanish qulayligi va moslashuvchanligi haqida ham. Bundan tashqari, UI ichidagi tugmani bosishning ishlash qiymati ham beparvo bo'ladi. Agar tugmachani emas, balki tugmachani bosmasa, tugmachani emas, balki tugma emas, tugmachani bosib tugmachani bosishingiz mumkin.
qo'shib qo'ydi muallif Ian Young, manba
Xulq-atvorni tugmachadan alohida bir narsa sifatida muomalada bo'lish yaxshi, deb o'ylayman, shuning uchun xatti-harakatlarni turli tugmachalarga qaytarishim mumkin. Garchi virtual funktsiyalar va boshlang'ich sinflarni yoqtirmasam-da. Ishonchim komilki, nima uchun bu narsa shaffoflikdan uzoqlashadi, deb o'ylayman va men buni oson ishlatish uchun ishlashdan tashqarida bo'lganim kabi his qilaman
qo'shib qo'ydi muallif Victor, manba

Siz atrofdagi narsalarni o'zingizning har bir ramkangizga o'girish va bajarishingiz mumkin

if(button(quadIndex)){
   //handle click
}

bu erda tugmasi (int) to'rtburchakni ko'rib chiqadi va o'yinchining o'sha joyga bosilganligini tekshiradi. Shu bilan birga, uni tuzish rejalashtiriladi.

Tekshiruv qutilarida siz davlatni ifodalovchi boolga ko'rsatuvchi o'tasiz

if(checkBox(quadIndex, &selected)){
   //handle that selected changed
}

if(selected){
    //...
}

Ushbu naqsh ba'zan zudlik bilan tartibli GUI deb ataladi.

0
qo'shib qo'ydi

virtual funktsiyasi bilan tugmacha bir mavhum sinf qiling.

Keyin tugma tugma-klikida nima qilish kerakligini amalga oshirib, bosish ni ishlatadigan har bir tugma uchun derivativ sinfi yarating.

0
qo'shib qo'ydi
@stimulate Nima uchun C echimini xohlasangiz, C ++ savolini tagiga qo'ygansiz? Bu erda past darajadagi ishlash ko'rsatkichlari ahamiyatga ega emas. Bir soniya ichida minglab klik voqealarini qayta ishlamaguningizcha, virtual uskuna qo'ng'iroq qilishning ustunlik darajasi muhim emas.
qo'shib qo'ydi muallif Philipp, manba
Men virtual funktsiyalardan va boshlang'ich sinflardan qochmoqchiman, chunki men aniq, funktsional dasturlash uslubiga tayanishni xohlayman. Ayniqsa mening dasturimning bu qismida juda ta'sirchan bo'lishi kerak.
qo'shib qo'ydi muallif Victor, manba