मैं एक आवरण वर्ग उदाहरण के साथ एक key_callback कैसे जोड़ सकता हूं?


11

मैं अपने GLFW3 कॉल को एक ही वर्ग में लपेटने की कोशिश कर रहा हूं:

class WindowManager {
private:
    GLFWwindow* window_;
    GLFWmonitor* monitor_;
    Keyboard* keyboard_;
...
}

और मैं एक सिंगलटन कीबोर्ड क्लास सेटअप करने की कोशिश कर रहा हूं जो निष्पादन के दौरान कुंजी दबाता है। GLFW में मैं एक key_callbackफंक्शन सेट कर सकता हूं जो क्लास डेफिनिशन (एक फ्री फंक्शन) के बाहर है:

WindowManager::WindowManager() {
    ...
    glfwSetKeyCallback(window_, key_callback);
    ...
}

// not a class function
void key_callback(GLFWwindow* window, int key, int scan code, int action, int mods) {
    ...
}

मैं अपने कॉलबैक और मेरे WindowManagerउदाहरण को कैसे जोड़ सकता हूं ताकि मैं keyboard_ऑब्जेक्ट वैल्यू सेट कर सकूं? मैं key_callbackसदस्य कार्य WindowManagerनहीं कर सकता क्योंकि वह कार्य नहीं करेगा क्योंकि वह कार्य WindowManager वर्ग का सदस्य होगा और C ++ सदस्य वर्ग के कार्य में उनके नाम खतरे में पड़ जाएंगे।

जवाबों:


11

मुझे भी इसी तरह की समस्या थी। यह कष्टप्रद है कि glfwSetWindowUserPointer और glfGetWindowUserPointer का उपयोग करने पर बहुत कम प्रलेखन है। यहाँ आपकी समस्या का समाधान है:

WindowManager::WindowManager() {
    // ...
    glfwSetUserPointer(window_, this);
    glfwSetKeyCallback(window_, key_callback_);
    // ...
}

void WindowManager::key_callback(GLFWwindow *window, int, int ,int, int) {
    WindowManager *windowManager =
      static_cast<WindowManager*>(glfwGetUserPointer(window));
    Keyboard *keyboard = windowManager->keyboard_;

    switch(key) {
        case GLFW_KEY_ESCAPE:
             keyboard->reconfigure();
             break;
     }
}

वैसे भी, क्योंकि यह C ++ कक्षाओं के साथ GLFW का उपयोग करने के लिए शीर्ष परिणामों में से एक है, मैं C ++ वर्ग में एक glfwWindow को एन्कैप्सुलेट करने की अपनी विधि भी प्रदान करूंगा। मुझे लगता है कि यह इसे करने के लिए सबसे सुरुचिपूर्ण तरीका है, क्योंकि यह ग्लोबल्स, सिंगलटन या यूनिक_प्रेटर्स का उपयोग करने से बचता है, प्रोग्रामर को विंडो को बहुत अधिक OO / C ++ - y शैली में हेरफेर करने देता है, और अनुक्रमण (लागत पर) की अनुमति देता है थोड़ा और अधिक अव्यवस्थित हेडर फ़ाइल)।

// Window.hpp
#include <GLFW/glfw3.h>
class Window {
public:
    Window();
    auto ViewportDidResize(int w, int h)             -> void;
    // Make virtual you want to subclass so that windows have 
    // different contents. Another strategy is to split the
    // rendering calls into a renderer class.
    (virtual) auto RenderScene(void)                 -> void;
    (virtual) auto UpdateScene(double ms)            -> void;
    // etc for input, quitting
private:
    GLFWwindow *m_glfwWindow;

    // Here are our callbacks. I like making them inline so they don't take up
    // any of the cpp file
    inline static auto WindowResizeCallback(
        GLFWwindow *win,
        int w,
        int h) -> void {
            Window *window = static_cast<Window*>(glfwGetUserPointer(win));
            window->ViewportDidResize(w, h);
    }
    inline static auto WindowRefreshCallback(
        void) -> void {
            Window *window = static_cast<Window*>(glfwGetUserPointer(win));
            window->RenderScene(void);
    }
    // same for input, quitting
}

और किसके लिए:

// Window.cpp
#include <GLFW/glfw3.h>
#include "Window.hpp"
Window::Window() {
    // initialise glfw and m_glfwWindow,
    // create openGL context, initialise any other c++ resources
    glfwInit();
    m_glfwWindow = glfwCreateWindow(800, 600, "GL", NULL, NULL);        

    // needed for glfwGetUserPointer to work
    glfwSetWindowUserPointer(m_glfwWindow, this);

    // set our static functions as callbacks
    glfwSetFramebufferSizeCallback(m_glfwWindow, WindowResizeCallback);
    glfwSetWindowRefreshCallback(m_glfwWindow, WindowRefreshCallback);
}

// Standard window methods are called for each window
auto
Window::ViewportDidResize(int w, int h) -> void
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
}

यह शायद एक WindowManager / InputManager वर्ग के साथ काफी आसानी से एकीकृत किया जा सकता है, लेकिन मुझे लगता है कि प्रत्येक विंडो को स्वयं प्रबंधित करना आसान है।


मैं कई वर्षों के बाद वापस आया और अद्यतन जवाब देखा। वास्तव में अच्छा एक धन्यवाद
ArmenB

स्थैतिक कार्यों में, आप एक वर्ग (यानी Window *window ) का एक नया उदाहरण बना रहे हैं । इससे समस्या का समाधान कैसे होगा?
क्रुको

मैंने देखा कि उत्तर कुछ नई C ++ सुविधाओं का समर्थन करने के लिए बदल गया है। क्या फ़ंक्शन रिटर्न प्रकार को ऑटो पर सेट करने का कोई लाभ है, और फिर टाइपिंग का उपयोग करके -> शून्य?
आर्मेनबी

5

कॉलबैक निशुल्क कार्य या स्थिर कार्य होने चाहिए, जैसा कि आपने पाया है। कॉलबैक GLFWwindow*स्वचालित thisसूचक के स्थान पर अपना पहला तर्क देता है ।

GLFW के साथ आप उपयोग कर सकते हैं glwSetWindowUserPointerऔर glfwGetWindowUserPointerस्टोर और के लिए एक संदर्भ को पुनः प्राप्त करने WindowManagerके लिए या एक प्रति-खिड़की Windowउदाहरण।

याद रखें कि GLFW किसी भी प्रकार के प्रत्यक्ष बहुरूपता के रूप में आभासी कार्यों का उपयोग नहीं करता है क्योंकि यह एक शुद्ध सी एपीआई है। इस तरह के एपीआई हमेशा मुफ्त कार्य करते हैं (सी में कोई वर्ग या सदस्य कार्य नहीं हैं, आभासी या अन्यथा) और मापदंडों के रूप में स्पष्ट "ऑब्जेक्ट इंस्टेंसेस" पास करते हैं (आमतौर पर पहले पैरामीटर के रूप में; सी में कोई नहीं है this)। गुड सी एपीआई में उपयोगकर्ता पॉइंटर कार्यक्षमता (कभी-कभी अन्य चीजों के बीच "उपयोगकर्ता डेटा" भी कहा जाता है) को शामिल किया जाता है ताकि आपको ग्लोबल्स का उपयोग न करना पड़े।

पुराना उत्तर:

यदि आपको अपने WindowManager(या अन्य प्रणालियों) में अन्य डेटा एक्सेस करने की आवश्यकता है , तो आपको कॉलबैक से इसे एक्सेस करना चाहते हैं, तो आपको उन्हें विश्व स्तर पर सुलभ होना चाहिए। उदाहरण के लिए, एक वैश्विक है std::unique_ptr<Engine>जिसे आप अपने विंडो मैनेजर तक पहुंचने के लिए उपयोग कर सकते हैं, या बस एक वैश्विक बना सकते हैं std::unique_ptr<WindowManager>( std::unique_ptrयदि आप चाहें तो "सिंगलटन के लिए कुछ बेहतर" के साथ बदलें )।

यदि आप एक से अधिक विंडो समर्थन चाहते हैं, तो आपके पास विंडो std :: unordered_map GLFWwindow * WindowManagerको मैप करने के लिए कुछ डेटा संरचना होगी। * उन्हें वे डेटा देखने के लिए प्राप्त हुए जिनकी उन्हें आवश्यकता है।GLFWwindow*' values to your ownclasses in some way, e.g. using aor the like. Your callback could then access the global and query the datastructure using the


आपके सहयोग के लिए धन्यवाद। इस तरह से एक परिदृश्य में, यह है कि यह सामान्य रूप से कैसे संभाला जाता है (कीबोर्ड इनपुट का ट्रैक रखने के लिए एक वैश्विक अनूठे_tr का उपयोग करके)? मैं इस तरह से किसी भी वैश्विक चर से बचना चाहता था और कीबोर्ड के कॉन्स्टेंट पॉइंटर्स के आसपास से गुजरना पसंद करता था जिसे इसकी आवश्यकता है लेकिन ऐसा लगता है कि यह संभव नहीं है, क्या मैं सही हूं?
अरमानबी

1
आमतौर पर एक Unique_ptr नहीं, लेकिन एक सिंगलटन का उपयोग करना असामान्य नहीं है। GLFW में खिड़कियों के लिए एक सेट उपयोगकर्ता डेटा फ़ंक्शन भी है जो वैश्विक की आवश्यकता से बच सकता है। अधिकांश "अच्छा" सी एपीआई में कुछ समान है। यह सुझाव देने के लिए उत्तर को अपडेट कर सकता है कि जब मैं असली कंप्यूटर पर वापस आता हूं।
शॉन मिडिलिच्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.