![]() |
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; |
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: |
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.
|
AW: Knob value wie feiner abstimmen
Zitat:
Das ist eine Komponente in Nonvcl Siehe mein VirtualPiano gruss |
AW: Knob value wie feiner abstimmen
Zitat:
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 |
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... |
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. |
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 |
AW: Knob value wie feiner abstimmen
Hab
![]() |
AW: Knob value wie feiner abstimmen
Zitat:
Zahlenskala ist vorhanden einmal direkt als String so das man den Endwert immer vor Augen hat. Und beim drehen als ToolTip.. EDIT: Zitat:
Siehe Anhang so sollte es sein. gruss |
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. |
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 :-) |
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. |
AW: Knob value wie feiner abstimmen
Zitat:
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 |
AW: Knob value wie feiner abstimmen
Kannst ja alle genannten mal umsetzen und dann einen Usability Test unter freiwilligen DP-Mitgliedern machen :mrgreen:
|
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 ![]() P.S. Und wenn du bei der grafischen Gestaltung der Knobs ein wirklich nettes Tool suchst, das nichts kostet, schau dir mal den ![]() |
AW: Knob value wie feiner abstimmen
Zitat:
Den verwende ich schon seit Anbegin der zeit;) gruss |
AW: Knob value wie feiner abstimmen
Zitat:
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:
Habe meinen alten ToolTip zwischen gespeichert.
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; Nur wo soll ich diesen wieder aktivieren ?? HEheheheee
Delphi-Quellcode:
grrrrummel..
// Setze den alten ToolTip für den Knob
SetToolTipText(WinHandle, PWideChar(sOldTip)); Hat sich erledigt :)
Delphi-Quellcode:
gruss
WM_KILLFOCUS:
begin if MouseWeel then begin // Setze den alten ToolTip für den Knob SetToolTipText(WinHandle, PWideChar(sOldTip)); MouseWeel:= False; end; end; |
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