wxDev.fr, le portail francophone consacré à wxWidgets ! ( The french portal for wxWidgets )  
Esp. membre
Recheche rapide



Recherche avancée
Statistiques
Membres inscrits :2359

Membres en ligne : 0
Invités en ligne : 1

Valid XHTML 1.0 Transitional

Valid CSS2

Menu forum (navigation):
Pages: 1 2  
 
Accueil » Accueil forums » Création de composants spécifiques
» Access violation
Conversation : Access violation
11-10-2010 14:54:20  Re: Access violation #26
mauvais (Membre)
Inscrit le : 19-09-2010
Messages: 32
Snippets: 0
Tutoriels: 0
Hors ligne
Bon ca commence a ressembler a ce que j'avais en tete :)

J'ai tenu compte de vos remarques - du moins de celles que j'ai comprises, et j'en ai profite pour nettoyer un peu le code.

Code wxWidgets:

#ifndef WXDIAL_H
#define WXDIAL_H
 
#include <wx/wx.h>
#include <math.h>
 
class wxDial : public wxPanel
{
public:
    wxDial(wxPanel *parent, int id, int radius, bool logtype, float value, float minvalue, float maxvalue);
    wxPanel *m_parent;
 
    wxTextCtrl *m_tcvalue;
 
    void OnPaint(wxPaintEvent& event);
    void OnClick(wxMouseEvent& event);
    void OnDrag(wxMouseEvent& event);
    void OnRelease(wxMouseEvent& event);
    void OnMouseLeaveWindow(wxMouseEvent& event);
    void OnDoubleClick(wxMouseEvent& event);
    void OnKeyboard(wxKeyEvent& event);
    void OnWheel(wxMouseEvent& event);
 
    void UpdateValueFromLed(void);
    void UpdateLedFromValue(void);
 
    bool m_log;            // 0: linear 1: log
    int m_radius;        // radius of the dial knob
 
    float m_pos;        // Current position of the dial cursor
    float m_minpos;        // Minimal position
    float m_maxpos;   
 
    int m_xpos;            // Coordinates of upper left corner in parent panel
    int m_ypos;
 
    bool m_click;        // Is mouse down on the widget?
 
    int m_cursor_org;    // mouse pointer height in client window
 
    float m_value;       
    float m_minvalue;
    float m_maxvalue;
 
    wxColor m_bg;        // Parent background colour
 
};
 
#endif


Code wxWidgets:

#include <wx/wx.h>
#include <wx/dcbuffer.h>
#include <wx/string.h>
#include "wxDial.h"
 
wxDial::wxDial(wxPanel *parent, int id, int radius, bool logtype, float value, float minvalue, float maxvalue)
    :wxPanel(parent, id)
{
    m_parent = parent;
    m_radius = radius;
    m_log = logtype;
    m_value = value;
    m_minvalue = minvalue;
    m_maxvalue = maxvalue;
    m_minpos = (float)(30.0/180.0*M_PI);
    m_maxpos = (float)(330.0/180.0*M_PI);
    m_xpos = 30;
    m_ypos = 50;
    m_click = false;
 
    // Get initial led position
    UpdateLedFromValue();
 
    SetSize(m_xpos, m_ypos, 2*m_radius, 2*m_radius + 24);
 
    SetBackgroundStyle(wxBG_STYLE_CUSTOM);        // required for wxBufferedPaintDC
 
    m_bg = m_parent->GetBackgroundColour();        // To redraw the backgound on the component
 
    m_tcvalue = new wxTextCtrl(m_parent, wxID_ANY, wxT(""), wxPoint(m_xpos+2, m_ypos+2*m_radius+4), wxSize(2*m_radius-4,20), wxTE_CENTRE | wxTE_PROCESS_ENTER);
    m_tcvalue->Show(false);
 
    Connect(wxEVT_PAINT, wxPaintEventHandler(wxDial::OnPaint));
    Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxDial::OnClick));
    Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxDial::OnClick));
    Connect(wxEVT_MOTION, wxMouseEventHandler(wxDial::OnDrag));
    Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxDial::OnRelease));
    Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxDial::OnRelease));
    Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(wxDial::OnMouseLeaveWindow));
    Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(wxDial::OnDoubleClick));
    Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(wxDial::OnWheel));
    m_tcvalue->Connect(wxEVT_CHAR, wxCharEventHandler(wxDial::OnKeyboard), NULL, this);
};
 
void wxDial::OnPaint(wxPaintEvent& event)
{
 
    wxAutoBufferedPaintDC dc(this);
 
    dc.SetBackgroundMode(wxTRANSPARENT);
 
    wxColour col1, col2;
    col1.Set(wxT("#000000"));
    col2.Set(wxT("#ffffff"));
 
    // Redraw background
    dc.SetBrush(wxBrush(m_bg));
    dc.SetPen(wxPen(m_bg, 1, wxTRANSPARENT));
 
    int height, width;
    GetSize(&width, &height);
    dc.DrawRectangle(0,0,width,height);
 
    //Draw outer circle
    dc.SetBrush(wxBrush(col2));
    dc.SetPen(wxPen(col1, 2, wxSOLID));
    dc.DrawCircle(m_radius, m_radius, m_radius);
 
    // Draw inner circle
    dc.SetPen(wxPen(col1, 2, wxSOLID));
    dc.DrawCircle(m_radius, m_radius, m_radius/2);
 
    // Led
    wxColour ledcolour;
    ledcolour.Set((m_click) ? wxT("#fa8e00") : wxT("#619e1b"));
    dc.SetPen(wxPen(ledcolour, 1, wxSOLID));
    dc.SetBrush(wxBrush(ledcolour));
    dc.DrawCircle(m_radius-sin(m_pos)*(3*m_radius/4), m_radius+cos(m_pos)*(3*m_radius/4), 5);
 
    //Text frame
    wxColour frameupcolour, framedwcolour, framebgcolour;
    frameupcolour.Set(wxT("#7a7a7a"));
    framebgcolour.Set(wxT("#5c3f21"));
    framedwcolour.Set(wxT("#c8c8c8"));
 
    dc.SetPen(wxPen(frameupcolour, 2, wxSOLID));
    dc.SetBrush(wxBrush(framebgcolour));
    dc.DrawRectangle(2, 2*m_radius+4, 2*m_radius-4, 20);
 
    dc.SetPen(wxPen(wxColor(framedwcolour), 2, wxSOLID));
    dc.DrawLine(2, 2*m_radius+24, 2*m_radius-2, 2*m_radius+24);
    dc.DrawLine(2*m_radius-2, 2*m_radius+24, 2*m_radius-2, 2*m_radius+4);
    // Text
    //if (!m_tcvalue->IsShownOnScreen()) {
    wxSize size = dc.GetTextExtent(wxString::Format(wxT("%3.1f"), m_value));
    dc.SetTextForeground(wxColour(193, 29, 11));
    dc.DrawText(wxString::Format(wxT("%3.1f"), m_value), width/2-size.GetWidth()/2, height-19);
 
 
 
    m_tcvalue->Raise();
    m_tcvalue->SetFocus();
    m_tcvalue->Refresh();
};
 
void wxDial::OnClick(wxMouseEvent& event)
{
    int y = event.GetY();
    // Don't do anything if it's a single click on the text field
    if (y <= 2*m_radius) {
        m_click = true;
        m_cursor_org = y;
        m_tcvalue->Show(false);
        Refresh();
    }
};
 
void wxDial::OnDrag(wxMouseEvent& event)
{
    // If control was not clicked priorly do nothing
    if ((event.m_leftDown ||event.m_middleDown) && m_click == true) {
        int y;
        y = event.GetY();
        // Dragging on the whole component is turning the dial form min to max
        m_pos += (float)(m_cursor_org-y)/(float)m_radius*M_PI;
        // Keep angle between min and max
        if (m_pos < m_minpos)
            m_pos = m_minpos;
        else if (m_pos > m_maxpos)
            m_pos = m_maxpos;       
        m_cursor_org = y;
        // Compute corresponding parameter
        UpdateValueFromLed();
        Refresh();
    }
};
 
void wxDial::OnRelease(wxMouseEvent& event)
{
    // Mouse up -> signal it and redraw so that cursor is modified accordingly
    m_click = false;
    Refresh();
};
 
void wxDial::OnMouseLeaveWindow(wxMouseEvent& event)
{
    // when mouse is out of window, turn off led
    if (m_click) {
        m_click = false;
        Refresh();
    }
};
 
void wxDial::OnDoubleClick(wxMouseEvent& event)
{
    // Check click is on the text field
    int y;
    y = event.GetY();
    // If it is, make edit visible and set string to dial current value
    if (y >= 2*m_radius) {
        m_tcvalue->SetValue(wxString::Format(wxT("%3.1f"), m_value));
        m_tcvalue->SelectAll();
        m_tcvalue->Show(true);
    }
};
 
void wxDial::OnKeyboard(wxKeyEvent& event)
{
    if (wxIsdigit(event.GetKeyCode()) || (event.GetKeyCode() == 46) || (event.GetKeyCode() == 43) || (event.GetKeyCode() == 45))
        event.Skip();
    else if (event.GetKeyCode() == WXK_RETURN) {
        double input;
        wxString sval = m_tcvalue->GetValue();       
        bool test_input = sval.ToDouble(&input);
        if (test_input && input >= m_minvalue && input <= m_maxvalue) {           
            m_value = (float)input;
            m_tcvalue->Show(false);
            UpdateLedFromValue();               
            }
        else {
            m_tcvalue->SetValue(wxString::Format(wxT("%3.1f"), m_value));
            m_tcvalue->SelectAll();
            wxBell();
        }
    }
    else if (event.GetKeyCode() == WXK_ESCAPE)
        m_tcvalue->Show(false);
    else
        wxBell();   
};
 
 
void wxDial::OnWheel(wxMouseEvent& event)
{
    int rot = event.GetWheelRotation();
};
 
void wxDial::UpdateValueFromLed(void) {
    if (!m_log)
        m_value = (m_pos-m_minpos)/(m_maxpos-m_minpos)*(m_maxvalue-m_minvalue) + m_minvalue;
    else
        m_value = m_minvalue*pow(m_maxvalue/m_minvalue, (m_pos-m_minpos)/(m_maxpos-m_minpos));
 
    // No need to refresh
};
 
void wxDial::UpdateLedFromValue(void) {
    if (!m_log)
        m_pos = (m_value-m_minvalue)/(m_maxvalue-m_minvalue)*(m_maxpos-m_minpos) + m_minpos;
    else
        m_pos = log(m_maxvalue/m_value)/log(m_maxvalue/m_minvalue)*(m_maxpos-m_minpos) + m_minpos;
 
    Refresh();
};


Nouveau probleme d'evenement, avec cette fois la roulette de la souris. Comme d'hab evenement pas detecte ;)
12-10-2010 23:57:35  Re: Access violation #27
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1383
Snippets: 25
Tutoriels: 6
Site web
Hors ligne
Salut.

Effectivement, même en rajoutant un "CaptureMouse" sur l'événement "EnterWindow" (et un "ReleaseMouse" sur le "LeaveWindow"), le MouseWheel n'est pas intercepté.

En fait, même s'il n'est pas visible, c'est le wxTextCtrl qui a le focus.

Pour palier à ce problème, il suffit de le désactiver lorsqu'il est caché (et de l'activer avant de l'afficher, sinon, il ne sert à rien).

Avec ça, l'événement MouseWheel est bien intercepté par wxDial.

Mais le wxTextCtrl n'est toujours pas au bon endroit.
Et le composant affiche une valeur bizarre quand on fait évoluer le curseur :
Je l'ai créé avec les valeurs mini et maxi = 0 et 50, ainsi qu'un valeur de départ de 10.
Le 10 est bien affiché en texte, mais apparement, le curseur est sur la position 0.
Et si je fais bouger ce dernier, la partie "texte" prend la valeur "-1.$"

@+
Xav'

Le nouveau portail wxWidgets francophone : www.wxdev.fr
Ben en fait, vous y êtes déjà...
13-10-2010 14:50:34  Re: Access violation #28
mauvais (Membre)
Inscrit le : 19-09-2010
Messages: 32
Snippets: 0
Tutoriels: 0
Hors ligne
Xaviou:
Salut.

Effectivement, même en rajoutant un "CaptureMouse" sur l'événement "EnterWindow" (et un "ReleaseMouse" sur le "LeaveWindow"), le MouseWheel n'est pas intercepté.

En fait, même s'il n'est pas visible, c'est le wxTextCtrl qui a le focus.

Pour palier à ce problème, il suffit de le désactiver lorsqu'il est caché (et de l'activer avant de l'afficher, sinon, il ne sert à rien).

Avec ça, l'événement MouseWheel est bien intercepté par wxDial.

Mais le wxTextCtrl n'est toujours pas au bon endroit.
Et le composant affiche une valeur bizarre quand on fait évoluer le curseur :
Je l'ai créé avec les valeurs mini et maxi = 0 et 50, ainsi qu'un valeur de départ de 10.
Le 10 est bien affiché en texte, mais apparement, le curseur est sur la position 0.
Et si je fais bouger ce dernier, la partie "texte" prend la valeur "-1.$"

@+
Xav'
Salut Xaviou,

En effet, j'ai un peu essaye ce soir et je recois maintenant l'evenement de la roulette. Merci!

Par rapport a ton probleme d'initialisation, prends garde a ne pas choisir une loi logarithmique (m_pos = 1) si le min est a 0 (ou negatif). En logarithmique, 0 c'est moins l'infini.

Cela etant il y avait une coquille tout de meme ;) Voici le code de la fonction corrigee:

Code wxWidgets:

void wxDial::UpdateLedFromValue(void) {
    if (!m_log)
        m_pos = (m_value-m_minvalue)/(m_maxvalue-m_minvalue)*(m_maxpos-m_minpos) + m_minpos;
    else
        m_pos = log(m_value/m_minvalue)/log(m_maxvalue/m_minvalue)*(m_maxpos-m_minpos) + m_minpos;
 
    Refresh();
};


C'est super que tu essayes le code de ton cote. Pour ma part je tourne pour l'instant sous windows avec Visual Studio et wxWidgets 2.8.11 - le but etant bien sur de voir comment ca se comporte sur les autres plateformes.

Quand je ferme l'application, Visual affiche:

Code:

Detected memory leaks!
Dumping objects (...) 100 bytes long


Tu as la meme chose?

A++

Nico
13-10-2010 23:44:36  Re: Access violation #29
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1383
Snippets: 25
Tutoriels: 6
Site web
Hors ligne
Hello

mauvais:
Par rapport a ton probleme d'initialisation, prends garde a ne pas choisir une loi logarithmique (m_pos = 1) si le min est a 0 (ou negatif). En logarithmique, 0 c'est moins l'infini.
Effectivement, en mettant le 4ème paramètre à false, le comportement est meilleur.
Je me demandais aussi à quoi il servait celui là.

Il reste toujours ce problème de wxTextCtrl qui est en dehors du composant alors que normalement (si j'ai bien tout compris) il devrait prendre la place du texte affiché sous le potentiomètre.

mauvais:
C'est super que tu essayes le code de ton cote. Pour ma part je tourne pour l'instant sous windows avec Visual Studio et wxWidgets 2.8.11 - le but etant bien sur de voir comment ca se comporte sur les autres plateformes.
Pour ma part, les tests se font sous Windows XP, Code::Blocks  (gcc 3.4.5), et wxWidgets-2.8.11.


mauvais:
Quand je ferme l'application, Visual affiche:

Code:

Detected memory leaks!
Dumping objects (...) 100 bytes long


Tu as la meme chose?
Ben pour être franc, je n'ai pas mis en place de détection, et j'ai un problème avec mon install de gdb qui ne veut pas s'exécuter correctement.
Si je trouve un moment, je ferais l'essai sous Visual C++, pour voir.

@+
Xav'

Le nouveau portail wxWidgets francophone : www.wxdev.fr
Ben en fait, vous y êtes déjà...
Menu forum (navigation):
Pages: 1 2  
 
Accueil » Accueil forums » Création de composants spécifiques
» Access violation