Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Knob value wie feiner abstimmen (https://www.delphipraxis.net/160288-knob-value-wie-feiner-abstimmen.html)

EWeiss 5. Mai 2011 22:57

Knob value wie feiner abstimmen
 
Jemand eine Idee wie ich mein Knob Controll noch feiner abstimmen kann?
Benutze schon single aber das scheint nicht auszureichen
da beim drehen der Knobs es sehr schwierig ist die benötigte Value zu treffen.
Manchmal springt es einfach 2 Frames weiter vor allem dann wenn ein ImageStrip wie bei Speed 300 Bilder enthält.

Gibt es da noch was akurateres als Single?

Delphi-Quellcode:
const
  KNOB_HORZ = -1;
  KNOB_VERT = 0;
  KNOB_NONE = 1;

  KNOB_GAP         = 45  * pi / 180;
  KNOB_ANGLE_RANGE = 2   * pi {360°} - KNOB_GAP;
  KNOB_OFFSET_ANGLE = 0.5 * pi {90°, also "unten"} + 0.5 * KNOB_GAP;

  KNOB_IMAGE        = 1;
  KNOB_MINVAL       = 2;
  KNOB_MAXVAL       = 3;
  KNOB_VALUE        = 4;
  KNOB_MOVING       = 5;
  KNOB_WAS_VALUE    = 6;
  KNOB_DEFAULT_VALUE = 7;
Delphi-Quellcode:
function ValueFromAngle(Angle: single): single;
var
  RelativeAngle: single;
begin
  RelativeAngle := Angle - KNOB_OFFSET_ANGLE;
  if RelativeAngle < 0 then
    RelativeAngle := RelativeAngle + 2 * pi;

  Result := (RelativeAngle) / KNOB_ANGLE_RANGE;
  if Result > 1.0 then
    if RelativeAngle < 0.5 * KNOB_ANGLE_RANGE + pi then
      Result := 1
    else
      Result := 0
end;

procedure UpdateFramePosition(WinHandle: HWND);
var
  Img, imgW, imgH: cardinal;
begin
  //with SkinEngine do
  //begin
    Img := SkinEngine.GetProperty(WinHandle, KNOB_IMAGE);
    SkinEngine.GetImageSize(Img, imgW, imgH);

    XOffset  := FFrame mod tmax;
    YOffset  := FFrame div tmax;
    dXOffset := integer(imgW) div tmax;
    dYOffset := 0;
  //end;

end;

procedure SetKnobLocation(WinHandle: HWND; x, y: single);
var
  rc:              TRect;
  Img, imgW, imgH: cardinal;

begin

  //with SkinEngine do
  //begin

    GetClientRect(WinHandle, rc);

    Img := SkinEngine.GetProperty(WinHandle, KNOB_IMAGE);
    SkinEngine.GetImageSize(Img, imgW, imgH);

    tMin := SkinEngine.GetProperty(WinHandle, KNOB_MINVAL);
    tMax := SkinEngine.GetProperty(WinHandle, KNOB_MAXVAL);

    Angle := arctan2(y - rc.Bottom div 2, x - rc.Right div 2);
    Value := ValueFromAngle(Angle) * tMax ;

    FFrame := round(Value) mod tMax;
    UpdateFramePosition(WinHandle);


    SkinEngine.SetProperty(WinHandle, KNOB_VALUE, round(Value));
    if Value <> SkinEngine.GetProperty(WinHandle, KNOB_WAS_VALUE) then
    begin
      SkinEngine.FUpdateWindow(WinHandle, False);
      SetToolTipText(WinHandle, PWideChar(IntToStr(round(Value))));
    end;

    SkinEngine.SetProperty(WinHandle, KNOB_WAS_VALUE, round(Value));
  //end;

end;

// Berechne die X, Y koordinaten abhängig von der aktuellen tVal
procedure GetKnobLocation(WinHandle: HWND);
var
  Img, imgW, imgH: cardinal;
begin

  //with SkinEngine do
  //begin
    Img := SkinEngine.GetProperty(WinHandle, KNOB_IMAGE);
    SkinEngine.GetImageSize(Img, imgW, imgH);
    tMax := SkinEngine.GetProperty(WinHandle, KNOB_MAXVAL);
    Value := SkinEngine.GetProperty(WinHandle, KNOB_VALUE);
    if Value <= (tMax - 1) then
    begin
      FFrame := round(Value) mod tMax;
      UpdateFramePosition(WinHandle);
    end else
    begin
       FFrame := round(Value - 1) mod tMax;
       UpdateFramePosition(WinHandle);
    end;
  //end;

end;

// Default Value setzen
procedure SetKnobDefaultValue(WinHandle: HWND; tVal: Integer);

begin

  //with SkinEngine do
  //begin
    tMin := SkinEngine.GetProperty(WinHandle, KNOB_MINVAL);
    tMax := SkinEngine.GetProperty(WinHandle, KNOB_MAXVAL);
    if tMin > tMax then
      SWAP(tMin, tMax);

    tVal := MIN(MAX(tMin, tVAL), tMax);
    if tVal <> SkinEngine.GetProperty(WinHandle, KNOB_VALUE) then
    begin
      SkinEngine.SetProperty(WinHandle, KNOB_VALUE, tVal);
      SkinEngine.SetProperty(WinHandle, KNOB_WAS_VALUE, tVal);

      SkinEngine.FUpdateWindow(WinHandle, False);
    end;
  //end;

end;

s.h.a.r.k 5. Mai 2011 23:11

AW: Knob value wie feiner abstimmen
 
Hab mir deinen Code jetzt nicht komplett angeschaut, aber ab und an verwende ich logarithmische Skalen und keine linearen.

Und was sind Knob Controls? :stupid:

Namenloser 5. Mai 2011 23:17

AW: Knob value wie feiner abstimmen
 
Es gibt akkurateres als Single, nämlich Double und Extended. Aber das wird dir hier nichts nützen, denn das Problem ist einfach, dass du den Mauszeiger nur in ganzen Pixelschritten bewegen kannst. Da du, wenn ich es recht in Erinnerung habe, den Bereich, indem man die Maus bewegen darf, auf den Bereich des Knobs beschränkst, hast du so nur sehr begrenzte Auswahl an möglichen Cursorpositionen. Lass dieses „Cursor-Clipping“ mal weg, dann kann man den Cursor in einem größeren Radius bewegen und hat so feinere Einstellmöglichkeiten.

EWeiss 5. Mai 2011 23:36

AW: Knob value wie feiner abstimmen
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1099187)
Hab mir deinen Code jetzt nicht komplett angeschaut, aber ab und an verwende ich logarithmische Skalen und keine linearen.

Und was sind Knob Controls? :stupid:

Ach mano ärger mich doch nicht!

Das ist eine Komponente in Nonvcl
Siehe mein VirtualPiano

gruss

EWeiss 5. Mai 2011 23:39

AW: Knob value wie feiner abstimmen
 
Zitat:

Zitat von NamenLozer (Beitrag 1099189)
Es gibt akkurateres als Single, nämlich Double und Extended. Aber das wird dir hier nichts nützen, denn das Problem ist einfach, dass du den Mauszeiger nur in ganzen Pixelschritten bewegen kannst. Da du, wenn ich es recht in Erinnerung habe, den Bereich, indem man die Maus bewegen darf, auf den Bereich des Knobs beschränkst, hast du so nur sehr begrenzte Auswahl an möglichen Cursorpositionen. Lass dieses „Cursor-Clipping“ mal weg, dann kann man den Cursor in einem größeren Radius bewegen und hat so feinere Einstellmöglichkeiten.

Das habe ich schon lange entfernt also die Maus wird nicht mehr im Knob festgehalten.

Hmm wenn ich mir das im steinberg SDK anschaue ist das extrem Akkurat.
So sollte es auch bei mir sein :)
Sonst bekommt der User krämpfe wenn er die Dinger drehen muss.

gruss

Medium 6. Mai 2011 00:04

AW: Knob value wie feiner abstimmen
 
Ich habe jetzt auch nicht allzu genau auf den Code geschaut, bin aber ebenfalls von der Einschätzung her eher bei Integer-Maus-Koordinaten als bei Float-Präzision als wahrscheinlichtem Problem. Die Genauigkeit dürfte selbst bei Single sehr locker reichen. Mit einem Low-Level-Mousehook käme man an jedes Fitzelchen Mausbewegung, auch sub-pixel genau. Vielleicht wäre das was.
Eine andere Idee wäre eine non-lineare Skala, die um wahrscheinlichste Werte (z.B. den beschrifteten, oder was auch immer der Einsatzzweck so fordert) höher auflöst - da könnte man mit einer Sinusfuktion z.B. was doktorn. Dat würd aber schon recht knifflig, und könnte sich auch komisch "anfühlen" - bewusst gesehen hab ich sowas noch nicht in freier Wildbahn :) Aber man kann ja mal so philosophieren...

s.h.a.r.k 6. Mai 2011 00:23

AW: Knob value wie feiner abstimmen
 
Andere Idee der Bedienung: User muss via Klick dieses Ding aktivieren und kann dann per Mausrad noch oben und unten steuern. So kannst du im Hintergrund eine Auflösung wählen, die dir passt und das dann halt entsprechend darstellen. Klar, wenn die Änderungen bei einem Dreh am Mausrad nicht all zu groß sind, dann sieht der Nutzer nicht unbedingt viel, daher sollte vielleicht noch eine Zahlenskala dazu geklatscht werden.

Oder: man kann diesen Knob steuern, wie bisher auch, was allerdings recht grob ist. Drückt der User zusätzlich Alt/Strg/Shift dann wird etwas feiner oder gröber gesteuert. Habe ich auch schon des öfteren gesehen.

EWeiss 6. Mai 2011 00:24

AW: Knob value wie feiner abstimmen
 
denke auch normalerweise dürfte single reichen.
Aber wie gesagt das ist nicht langsam(fein) genug so das man wirklich jede
Value erwischt.

Teste mal das angehängte projekt ;)
So sollte es sein.

VST Plugin Analyser starten und die DLL(Plugin) Advanced Clipper.DLL einladen.
Anschließend mal die Knobs drehen.

So sollte es sein bekomme es aber nicht hin mit meinem Controll.

gruss

s.h.a.r.k 6. Mai 2011 00:25

AW: Knob value wie feiner abstimmen
 
Hab meinen Beitrag oben nochmals editiert! Hatte da noch zusätzlich eine Idee.

EWeiss 6. Mai 2011 00:26

AW: Knob value wie feiner abstimmen
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1099195)
Andere Idee der Bedienung: User muss via Klick dieses Ding aktivieren und kann dann per Mausrad noch oben und unten steuern. So kannst du im Hintergrund eine Auflösung wählen, die dir passt und das dann halt entsprechend darstellen. Klar, wenn die Änderungen bei einem Dreh am Mausrad nicht all zu groß sind, dann sieht der Nutzer nicht unbedingt viel, daher sollte vielleicht noch eine Zahlenskala dazu geklatscht werden.

Oder: man kann diesen Knob steuern, wie bisher auch, was allerdings recht grob ist. Drückt der User zusätzlich Alt/Strg/Shift dann wird etwas feiner oder gröber gesteuert. Habe ich auch schon des öfteren gesehen.

Mit dem MausRad wäre eine Alternative.
Zahlenskala ist vorhanden einmal direkt als String so das man den Endwert immer vor Augen hat.
Und beim drehen als ToolTip..

EDIT:
Zitat:

Drückt der User zusätzlich Alt/Strg/Shift dann wird etwas feiner oder gröber gesteuert. Habe ich auch schon des öfteren gesehen.
Darum geht es mir ja die Frage nur wie muss mal schaun ob ich mit double da mehr erreiche.
Siehe Anhang so sollte es sein.

gruss

s.h.a.r.k 6. Mai 2011 00:30

AW: Knob value wie feiner abstimmen
 
Oder du wertest nicht die Pixel aus, die der User mit der Maus fährt, sondern löst das feiner auf. Aber das ist dann auch nicht mehr all zu toll, wenn ich 200 Pixel nach rechts z.B. fahren muss, dass sich da ein wenig was bewegt.

-- Edit: Schau mir mal das Bin.rar an.

-- Edit: Also, wenn mich nicht alles täuscht ist das eine logrithmische Skala. Im unteren Bereich wird pro Pixel, die sich die Maus bewegt sehr fein aufgelöst, und ab 1.0db wird pro Pixel 0.2db hinzugezählt bzw. abgezogen.

blackfin 6. Mai 2011 01:28

AW: Knob value wie feiner abstimmen
 
Vielleicht nur mal so als Denk-Ansatz:
Ich hatte mir vor ein paar Jährchen mal ein MIDI-Pult aus ein paar Microcontrollern, Touch-Motor-Fadern und echten "Knobs", also Endlos-Incremental-Encodern gebaut.
Da war die Auflösung auch anfangs ein Problem (Die mittelpreislichen Encoder haben eine ähnliche miese Hardware-Auflösung mit ca. 32-64 Takten/Umdrehung, was man mit der niedrigen Pixel-Auflösung einer Maus vergleichen kann).
Meine Lösung hat dann darauf basiert, dass ich die Auflösung / Wertesprünge, die über den Encoder z.B. an ein VST-Plugin übergeben werden, mit einem Beschleunigungsfaktor gesetzt habe, je nachdem, wie schnell jemand einen Knob / Encoder dreht. Bei langsamen Bewegungen sehr niedriges Increment / Decrement, bei schnellen, zackigen Bewegungen und gleichbleibender Greycode-Änderung dementsprechend weitere Wertesprünge. Diese Beschleunigungs-Tabellen (Greycode-Iterationen / Zeit => Sprungwert) waren dann im Pult auch änderbar.
Das wird zwar denke ich mit der Maus in einer PC-Application generell ein wenig schwieriger werden (Zeit messen in einem extrem kurzen Zeitbereich ohne HW-Interrupts wie bei einer MCU ja nicht so ohne weiteres möglich...), aber ich will das mal als Ansatz stehen lassen :)

Edit:
Echte Studio-Geräte (z.B. die meisten EQs und Kompressoren) haben bei Einstellungen über Drehregler auch oft mehrere "Bereich"-Buttons unter oder neben dem Encoder, die nach Aktivierung eben die gerade aktive Auflösung des Encoders festlegen. So etwas könnte man bei einem GUI-Knob auch relativ userfreundlich gestalten, indem man z.B. durch Klick auf den Knopf (mouse down + up ohne zwischenzeitliches Ziehen) die Auflösungen durchschaltet / rotiert und zusätzlich dann die Auflösung / Pixel neben dem Encoder anzeigt, dessen Farbe ändert oder wie auch immer. Oder eben mit der rechten Maustaste durchschalten lassen. Zuätzliche Keys wie SHIFT oder CTRL abfragen halte ich nicht so für gut, kommt aber auf den Anwendungsfall an. Im Soundbereich ist so etwas eher lästig (meine Meinung), da man die andere Hand meistens eh für andere Aktionen benötigt. Aber das ist Geschmacksache :-)

s.h.a.r.k 6. Mai 2011 01:36

AW: Knob value wie feiner abstimmen
 
Jo, hört sich nicht all zu einfach an, ABER du hast ein super Stichwort genannt, welches, passend implementiert, natürlich auch funktionieren kann. Und zwar spiele ich hier auf das (Teil-)Wort Endlos an, wobei ich nicht einen Knob meine, den man endlos drehen können soll, aber warum sollte nicht mehr als 360 Grad möglich sein?

Beispiel: Wenn du die doppelte Auflösung brauchst, dann sollten halt 720 Grad möglich sein und nicht nur 360.

EWeiss 6. Mai 2011 01:56

AW: Knob value wie feiner abstimmen
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1099201)
Jo, hört sich nicht all zu einfach an, ABER du hast ein super Stichwort genannt, welches, passend implementiert, natürlich auch funktionieren kann. Und zwar spiele ich hier auf das (Teil-)Wort Endlos an, wobei ich nicht einen Knob meine, den man endlos drehen können soll, aber warum sollte nicht mehr als 360 Grad möglich sein?

Beispiel: Wenn du die doppelte Auflösung brauchst, dann sollten halt 720 Grad möglich sein und nicht nur 360.

Danke euch für die Anregungen.
Habe es jetzt so umgesetzt das man nach einem Klick oder Drehen des Knobs den Focus auf
den Knob bekommt danach ist es dann möglich über Mousewheel die Feineinstellung vorzunehmen.

Irgendwie ist das doppelt gemoppelt.
Aber ne andere Idee hab ich da zur zeit auch nicht.

gruss

s.h.a.r.k 6. Mai 2011 02:01

AW: Knob value wie feiner abstimmen
 
Kannst ja alle genannten mal umsetzen und dann einen Usability Test unter freiwilligen DP-Mitgliedern machen :mrgreen:

blackfin 6. Mai 2011 02:05

AW: Knob value wie feiner abstimmen
 
Du kannst dir auch mal die Demo-Versionen von virtuellen Instrumenten anschauen, oft finden sich dort in der Praxis sehr ansprechende Lösungswege.
Empfehlenswert sind z.B. die GUIs der Tools von Native Instruments.

P.S.
Und wenn du bei der grafischen Gestaltung der Knobs ein wirklich nettes Tool suchst, das nichts kostet, schau dir mal den KnobMan an :-)

EWeiss 6. Mai 2011 02:26

AW: Knob value wie feiner abstimmen
 
Zitat:

Zitat von blackfin (Beitrag 1099204)
Du kannst dir auch mal die Demo-Versionen von virtuellen Instrumenten anschauen, oft finden sich dort in der Praxis sehr ansprechende Lösungswege.
Empfehlenswert sind z.B. die GUIs der Tools von Native Instruments.

P.S.
Und wenn du bei der grafischen Gestaltung der Knobs ein wirklich nettes Tool suchst, das nichts kostet, schau dir mal den KnobMan an :-)

Kann ja mal schaun schaden kann es nix :) Wobei die hier auf VSTGUI ausgelegt sind... Mach dann lieber mein eigenes weiter .. hiihiihihi
Den verwende ich schon seit Anbegin der zeit;)

gruss

EWeiss 6. Mai 2011 02:35

AW: Knob value wie feiner abstimmen
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1099203)
Kannst ja alle genannten mal umsetzen und dann einen Usability Test unter freiwilligen DP-Mitgliedern machen :mrgreen:

Wäre ja wohl ein bißchen hart :)
Muss jetzt nur mal sehen wo ich meinen alten TollTip Text wieder aktiviere nach dem MouseWeel.

Das ist etwas kompliziert da ich ja kein up/down habe wie bei Buttons

Delphi-Quellcode:
      WM_MOUSEWHEEL:
      begin
        if not MouseWeel then
        begin
          // hole den aktuellen ToolTip und speichere
          // ihn in die Variable sOldTip
          hToolTip := ToolTipData(0, 0);
          sOldTip := SkinEngine.GetCTLText(hToolTip);
          MouseWeel:= True;
        end;

        If wP > 0 then
          direction := 1
        else
        direction := -1;
        // Aktuelle Value einlesen
        WasValue := SkinEngine.GetProperty(WinHandle, KNOB_WAS_VALUE);
        if direction = 1 then
          // Neue Value um eins incrementieren
          tVal := WasValue + 1
        else
        // Neue Value um eins decrementieren
        tVal := WasValue - 1;

        // Poperties der aktuellen Value speichern
        SkinEngine.SetProperty(WinHandle, KNOB_VALUE, tVal);
        SkinEngine.SetProperty(WinHandle, KNOB_WAS_VALUE, tVal);
        // Aktuelle Value an die Anwendung schicken
        SendMessage(GetParent(WinHandle), WM_COMMAND,
          MAKELONG(GetDlgCtrlID(WinHandle), 0), SkinEngine.GetProperty(WinHandle, KNOB_VALUE));
        // Frame Aktualisieren
        FFrame := tVal;
        // Value ToolTip setzen
        SetToolTipText(WinHandle, PWideChar(IntToStr(tVal)));
        // XOffset Aktualisieren
        UpdateFramePosition(WinHandle);
        // Knob Neuzeichnen
        SkinEngine.FUpdateWindow(WinHandle, False);
      end;
Habe meinen alten ToolTip zwischen gespeichert.
Nur wo soll ich diesen wieder aktivieren ?? HEheheheee

Delphi-Quellcode:
// Setze den alten ToolTip für den Knob
SetToolTipText(WinHandle, PWideChar(sOldTip));
grrrrummel..

Hat sich erledigt :)
Delphi-Quellcode:
      WM_KILLFOCUS:
      begin
        if MouseWeel then
        begin
          // Setze den alten ToolTip für den Knob
          SetToolTipText(WinHandle, PWideChar(sOldTip));
          MouseWeel:= False;
        end;
      end;
gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:27 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz