Steuerelement Slider: Positionsänderung des Anzeigers direkt nach Änderung der Länge des Sliders



  • Hallo wissende Menschen da draußen,

    im Moment bastle ich einen Dialog, bei das meiste so funktioniert wie es soll. Einziges Sorgenkind ist der Slider. Es gibt 2 Editfelder "länge" und "position" die beiden einen int-Wert erwarten. Dadrüber ist der angesprochender Slider.
    Gebe ich einen anderen Wert bei "position" ein, soll die Position des Sliders verändert werden (funktioniert).
    Wird der Slider verändert, verändert sich auch die int Zahl im "position"sfeld (funktioniert).
    Nun zur "länge": wenn die position gerade 50 ist und ich die länge von 100 auf 200 ändere, dann muss der Slider von der Mitte ins erste Viertel springen. Das funktioniert leider nicht sofort, sondern erst wenn ich auf den Slider direkt klicke. Auch wenn ich im Editfeld "position" etwas ändere, merke ich das der slider seine absolute Länge gewünscht geändert haben muss.
    Wie bekomm ich das hin, dass das ganze sofort gemacht wird? Und nicht erst nach klick-experimente.
    Habe über die SuFu nichts gefunden.
    Ich hab das über den Assistenten. Es wird auf die Meldung BN_KILLFOCUS reagiert.
    Wäre nett wenn wir jemand weiterhlfen oder mich verweisen kann.

    void CXXDlg::OnEnKillLaenge()
    { 
    	UpdateData(true);
    
    	ctrSlider.SetRange(0, uiEditLaenge);
    	ctrSlider.SetPos(m_uiEditPosition);
    	UpdateData(false);
    

    IDE:Visual Studio 2005; MFC



  • Was meinst du mit "sofort"? In einer Echtzeiteingabe? Wie du schon gesagt hast, dein Slider soll sich ändern wenn sich das Edit ändert (ändern (dt.) = change (eng)).
    Wieso reagierst du dann in den Edits auf EN_KILLFOCUS?! Dann wird dein Handler erst aufgerufen, sobald dein Edit den Focus verliert, sprich, wenn du irgendwo anders drauf klickst, z.B. auf deinen Slider. Für eine "Echtzeitverarbeitung" musst du in deinen Edits auf EN_CHANGE reagieren...



  • Mit "sofort" ist gemeint, immer wenn der Benutzer wegklickt. Egal wohin. So wie bei der positionsänderung, man gibt etwas ein -> klickt weg -> position des Sliders ändert sich
    In Echtzeit würde ich es als etwas störrend empfinden.
    Hier möchte ich haben: andere länge eingeben -> klickt weg -> position des Sliderspfeil ändert sich (weil ja die Relation der absoluten position im Editfeld zu neuen Länge im anderen Editfeld nun eine andere ist)
    Genau das funktioniert nicht beim wegklicken, sondern beim klicken auf den slider direkt oder beim Ändern der position.
    Ich hoffe darauf, dass es eine Funktion gibt, die das erscheinungsbild "updated"



  • Also, der Code von oben ist sowohl Murks als auch überhaupt nicht hilfreich. Poste doch mal vernünftigen Code. Zeig deine MessageMap und den Teil, in dem du deine Strings ausliest, umwandelst usw. Und deine Slider-Funktion (was passiert wenn du da drauf klickst).

    Was die Meldung EN_KILLFOCUS tut, hab ich bereits beschrieben. Mit "egal wohin" wirst du nicht weit kommen. Ein Objekt verliert erst dann den Focus wenn ihn ein anderes Objekt bekommt.
    Verstehe ich das richtig, dass es bei der Position funktioniert aber bei der Länge nicht?



  • Ich drücke mich unpräzise aus. Entschuldige, ich bemüh mich. Danke dass du mir trotzdem hilfst.
    Ja, ich weiß was EN_KILLFOCUS tut. Es ist eine Meldung die von einem Ereignishandler verarbeitet wird. Die Meldung wird ausgelöst wenn ein anderes Fenster (oder eine Instanz einer Klasse die von Wnd erbt) den Fokus bekommt.
    Mit „egal wohin“ meine ich natürlich ein anderes Steuerelement. EN_KILLFOCUS wird ja auch im Programm geworfen und OnEnKillLaenge() aufgerufen. Auch SetRange und SetPos funktionieren anscheinend. Nur das Erscheinungsbild des Sliders ändert sich nicht, wie es müsste. Nämlich: der Zeiger an dem Slider müsste sich bei der Änderung der Länge auch verändern. Beispiel: Länge = 100, Position = 50, Slider-Regler ist in der Mitte. Änderung der Länge = 200, Position = 50, Slider-Regler müsste nach dem ersten Viertel stehen. Und dieser Reglersprung funktioniert nicht, der Regler bleibt einfach in der Mitte. Er ändert sich erst, wenn ich auf den Slider klicke oder die Position (über SLider oder Edit) verändere. Also Länge = 200, Position = 51, Slider spring fast genau in die Mitte. Das soll aber funktionieren, wenn auf irgendein beliebiges Steuerelement geklickt wird.
    Zum Code: Sry, ich dachte man sieht eventuell den Fehler sofort. Ich such mal alles relevante zusammen.
    Die MessageMap ist vom Assistenten gemacht und funktioniert.
    Ich lese von Editboxen, die nur UINTs annehmen können (keine Strings, also keine Umwandlung oä). Sie werden über ihre zugewiesenen Membervariablen mithilfe DDX eingelesen.

    // m_uiEditPosition = Value Variabale der Editbox (Position)
    // m_uiLaenge = Value Variabale der Editbox (Länge)
    // IDC_SLIDER = ID des Sliders
    // ctrSlider = Controll Variable des Sliders
    void CXXDlg::OnEnKillfocusEditPosition() //wird aufgerufen, wenn man von der Editbox Position wegklickt (auf ein anderes Steuerelement)
    {
    	UpdateData(true);
    	ctrSlider.SetPos(m_uiEditPosition);
    }//funktioniert
    
    void CXXDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) //wird aufgerufen wenn irgendein horizontaler Slider scrollt
    {
    	UpdateData(true);
    
        if (pScrollBar->GetDlgCtrlID()==IDC_SLIDER)
    	{
    		 m_uiEditPosition = ctrSlider.GetPos();
    		 UpdateData(false);
    	}
    
    	CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
    }//funktioniert
    void CXXDlg::OnEnKillfocusEditLaenge() //wird aufgerufen, wenn man von der Editbox Längewegklickt (auf ein anderes Steuerelement) 
    { 
    
    	UpdateData(true);
    
    	ctrSlider.SetRange(0, m_uiLaenge);
    	m_ctrSliderLength1.SetPos(m_uiEditPosition);
    
    	UpdateData(false);
    
    }//ändert Variablen aber Erscheinungsbild nicht
    

    Eine Vermutung: Ich muss den Focus auf den Slider setzten, dann wird sein Erscheinungsbild aktualisiert (es wird ja auch bei einem Klickt auf selbigen aktualisiert). Dazu müsste ich es schaffen, den Focus des Steuerelement auf das der Benutzer geklickt hat zu speichern(dadurch hat er ja EN_KILLFOCUS ausgelöst), den Focus kurz auf den Slider zu setzten und dann wieder auf das Steuerelement des Benutzers. Kann das gehen? (So gibt es kein Error aber es funktioniert auch nicht. Ob Denkfehler oder falscher Code, weiß ich nicht)

    Wird am Ende von OnEnKillfocusEditLaenge ausgeführt:

    CWnd *tempControllWindow = GetFocus();
    m_ctrSlider.SetFocus();
    (*tempControllWindow).SetFocus();
    

    Nochmal zu EN_CHANGE: Es ist deswegen ungeeignet, weil es ja bei jeder kleinen änderung reagiert. Also auch bei jeder Ziffer einer längeren Zahl. Es soll aber erst reagiert werden, wenn der Benutzer fertig ist und das ist er wenn er wegklickt und etwas anderes bearbeitet. Der Zeitpunkt ist nicht brilliant, aber entsprechend den Bedürfnissen schon okay so.



  • UpdateData(true);
     
        ctrSlider.SetRange(0, m_uiLaenge);
        m_ctrSliderLength1.SetPos(m_uiEditPosition);
    

    Wieso hast du auf einmal 2 Variablen für deinen Slider?!

    Ich erinnere mich dunkel... da war irgendwas:
    Füg zwischen SetRange() und SetPos() mal ein "ctrSlider.SetTicFreq(1);" ein.

    ctrSlider.SetRange(0, m_uiLaenge);
    ctrSlider.SetTicFreq(1);
    ctrSlider.SetPos(m_uiEditPosition);
    

    Und die ganzen UpdateDatas kannste hier weglassen denk ich...



  • Es funktioniert 😃 Juhu! Danke!

    Das

    UpdateData(false)
    

    kann weg, aber das

    UpdateData(true)
    

    muss bleiben.

    Jetzt werde ich ncoh die Doku bemühen, warum das funktioniert. Die Funktion ändert ja nur die Teilstriche. Aber hammer, dass es funktioniert 🙂


Anmelden zum Antworten