VST实例绘制VST

Posted Luo大哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VST实例绘制VST相关的知识,希望对你有一定的参考价值。

在绘制以及事件中,需要明确两个名词:

ITEM,通常指的是node,因为VST中一个节点就是一项。

CELL(单元格),通常指的是一个VST下的某具体栏(column)。

1、节点图标

VST可以链接两组图标,分别是vst.Images; vst.StateImages; vst.Images用于存储VST的通用图标,而vst.StateImages用于存储在不同状态下的图标。

事件OnGetImageIndex用于设置在不同情况下的图标,本程序的代码如下:

procedure TForm2.vstGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean;
  var ImageIndex: TImageIndex);
begin
   if (Column=2) and (Kind=ikNormal) then
     ImageIndex:=Sender.GetNodeLevel(node)+1;
end;

上面的代码中,column=2,用于指定只在第三栏中显示图标,Kind=ikNormal说明正常情况下的显示图标。实际上,大部分时候每个节点都有个状态:normal,但是,处于编辑状态或其它特殊情况时,则不具备normal状态。

kind有以下状态:

    ikNormal

    ikSelected 

    ikState,

  ikOverlay

如果不指定状态,则会同时显示两个图标,一个是normal的图标,一个是状态图标。

上面指定了kind=iknormal,因此如果选中某行节点的时候,你会看到没有图标,所以语句可以更改为:

if (Column=2) and (Kind in [ikNormal,ikSelected ])

如果没有kind部分,则VST显示的效果如下:

 

请注意:OnGetImageIndex事件的程序不同版本有所区别,V7.X和V5.X并不兼容。

默认情况下,VST每个单元格(CELL,即某个node下的某个column)都可以有图标,所以需要指定具体需要显示图标的node和column的图标ID(imageindex)。

2、绘制循环

绘制VST的顺序如下:

  • 开始绘制之前 (OnBeforePaint)
  • 节点绘制之前 (OnBeforeItemPaint)
  • 节点擦除之前 (OnBeforeItemErase)
  • 节点擦除之后 (OnAfterItemErase)
  • 单元格绘制之前 (OnBeforeCellPaint)
  • 绘制文本(string trees only, OnPaintText)
  • 绘制结束 (OnAfterCellPaint)

1OnBeforePaint

此事件发生在绘制VST之前,一个VST指发生一次此事件。

这个阶段通常用于对绘画操作的目标画布(TargetCanvas)(例如窗口或打印机画布)进行进一步设置,比如更改映射模式或设置另一个裁剪区域。由于传递的画布并不直接用于进行实际绘画,因此设置其字体或颜色没有任何效果。基本上,仅影响将位图复制到目标画布的属性才有任何影响。

通常不使用此事件,除非打算定制VST的背景图(background)。本程序没有使用此事件。

2OnBeforeItemPaint

当准备绘制某个node之前,会触发此事件。

在这个阶段的事件中,您可以告诉树形结构是否要完全自己绘制节点,还是让树形结构绘制它。由于这是基于每个节点的,所以这是保持特殊布局而不必在绘画循环中进行所有操作的完美场所。注意:将事件中的CustomDraw参数设置为True将完全跳过节点的绘制,不会绘制像树形线、按钮、图片或擦除背景等标准内容的任何东西。因此,要显示节点的任何有用信息,请在OnBeforeItemPaint事件中进行。

这是第一个获取双缓冲画布用于绘制节点的阶段,因此如果您想设置特殊属性,这是一个很好的机会。请记住,特别是颜色是由树形结构根据特定规则设置的(焦点、选择等)。

注意:如果你设置了CustomDraw:=true,那么后面你将自己绘制所有的东西,VST不会帮你绘制文本、图标等。

此时也不会进行任何实际的绘制,因此本程序也无此事件的代码。

3onBeforeItemErase

英语的erase通常翻译为擦除,但和我们理解中的擦除不一样,它并不是减去某种属性,而是在选定的区域都附上某种属性,例如擦除的位置,都使用某种颜色,而区域的之外,则是其原本的颜色。

事件onBeforeItemErase发生在开始绘制节点(node)之前,这个阶段及其相关事件通常用于为节点设置不同的背景颜色或用与树形结构不同的特殊图案擦除背景。

代码如下:

procedure TForm2.vstBeforeItemErase(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
  var ItemColor: TColor; var EraseAction: TItemEraseAction);
begin
  if Odd(NoDe.Index) then ItemColor:=clSilver;
end;

itemcolor指的是节点的背景色,如果没有在后面进行修改,则将在此处指定节点的背景色。

TItemEraseAction有三个值:

eaColor,   // 使用提供的颜色绘制背景。

eaDefault, // VST将绘制节点的背景(图形或颜色)

eaNone//将忽略颜色或图形的设置,使用上一个节点的颜色绘制背景。

需要注意的是,如果选择了eanone,在后面的程序中如果自己手动绘制了单元格,可能会出现文本的重影。

4OnAfterItemErase

此事件发生在完成节点背景绘制之后,每个节点只触发一次此事件,这个阶段及其相关事件用于在背景被擦除后进行额外的绘制。

本程序也无此事件的代码。

5onbeforecellpaint

此事件发生在绘制单元格之前,虽然在进入这个阶段之前(如果是第一次运行)已经进行了针对该节点的完整设置,但与onbeforeitemerase相比,此事件的不同之处是绘画被限制在当前列。现在还没有绘制线条或图片。

可在此事件中设置单元格的rect。本程序也没有此事件的代码。

6OnPaintText

此事件是VST特有的,而VDT没有此事件,用于文本绘制的设置,因为Virtual Treeview不知道如何绘制节点的内容,它将这个绘画委派给名为DoPaintNode的虚方法。派生类会覆盖此方法并执行适当的操作。例如,TVirtualDrawTree仅触发其OnDrawNode事件,而TVirtualStringTree准备目标画布,并允许应用程序通过触发OnPaintText重写一些或所有画布设置(字体等)。在此事件返回后,节点的文本/标题被绘制。当对齐和绘制文本时,改变的字体属性会被考虑在内。

本程序中此事件的代码如下:

procedure TForm2.vstPaintText(Sender: TBaseVirtualTree;
  const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType);
begin
  if Sender.Selected[node] then
  begin
    TargetCanvas.Font.Size:=14;
    TargetCanvas.Font.Style:=TargetCanvas.Font.Style+[fsUnderline,fsItalic];
  end;
end;

当某行节点被选择,则选择的文本有着不同的字体大小和样式。

此事件通常也不进行具体的绘制工作,具体的绘制工作在ondrawtext事件中写代码,也就是说,在此事件中通常只进行设置。事件ondrawtext的讲述将放到“3、绘制文本”中。

7OnAfterCellPaint

此事件发生于完成了单元格的绘制,此时已经完成单元格的绘制,包括选择框的绘制。

本程序也无此事件的代码。

3、绘制文本

文本的绘制在ondrawtext事件中实现,先上代码如下:

procedure TForm2.vstDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas;
  Node: PVirtualNode; Column: TColumnIndex; const Text: string;
  const CellRect: TRect; var DefaultDraw: Boolean);
var ss1,ss2:string; POS:Integer;  fc:TColor;fs:Integer;
begin
  case Column of
    0,1,3:
    begin
      //首先存储默认的字体大小和色号
      fc:=TargetCanvas.Font.Color;
      fs:=TargetCanvas.Font.Size;
      //SS1中存储特定文本,即lbledt1.Text,但转换为大写并清除前后的无用空格
      ss1:=lbledt1.Text;
      ss1:=ss1.Trim.ToUpper;
      //lbledt1为空或单元格中文本不包含lbledt1中的文本,则直接退出。
      if ss1.IsEmpty then Exit;
      if not Text.Contains(ss1) then Exit;
      //必须设置DefaultDraw为false,不然即便你自己对文本进行了绘制,
      //VST仍然会再次进行默认的绘制。
      DefaultDraw:=False;
      //根据不同的栏目和level进行不同的缩进
      if Column=0 then POS:=sender.GetNodeLevel(node)*10
      else
        POS:=0;
      //SS2暂时存储特定文本之前部分的文本,例如单元格文本是ZBAA,而SS1是BA,则SS2是Z
      SS2:=Text.Substring(0,TEXT.IndexOf(SS1));
      //如果SS2不为空
      if not ss2.IsEmpty then
      begin
        TargetCanvas.Font.Color:=fc;
        TargetCanvas.Font.size:=fs;
        TargetCanvas.TextOut(CellRect.left+POS,5,ss2);
        pos:=TargetCanvas.TextWidth(ss2)+POS+2;
      end;
      //字号12,颜色红色显示特定的文本
      TargetCanvas.Font.Color:=clRed;
      TargetCanvas.Font.size:=fs+2;
      TargetCanvas.TextOut(CellRect.left+POS,4,ss1);
      pos:=pos+targetcanvas.TextWidth(ss1)+2;
      //正常显示剩下的文本
      TargetCanvas.Font.Color:=fc;
      TargetCanvas.Font.size:=fs;
      ss2:=Text.Substring(ss2.Length+ss1.Length);
      TargetCanvas.TextOut(CellRect.left+POS,5,ss2);

    END;
    4:
    begin
      with pcodes(Sender.GetNodeData(NODE))^ do
      begin
        if rwy_style=\'单跑道\' then
        begin
          DefaultDraw:=False;
          TargetCanvas.Font.Color:=clRed;
          TargetCanvas.Font.size:=12;
          TargetCanvas.TextOut(cellrect.Left+3,CellRect.Top+5,\'\');
          TargetCanvas.Font.Color:=clBlack;
          TargetCanvas.Font.size:=10;
          TargetCanvas.TextOut(cellrect.Left+18,CellRect.Top+5,\'跑道\');
        end;
      end;
    end;
    else ;
  end;
end;

这段代码对显示的文本进行了定制,总得来说,代码分成了两部分,第一部分针对的是第一栏、第二栏和第四栏,如果ICAO四字码、IATA三字码或机场/情报区名称中存在查询的字符,则查询的字符放大两号,且以红色显示,而其余部分则以10号字体。

第二部分以红色字体显示单跑道的“单”字,其余正常显示。

显示结果如下:

 

 

 

VST SDK & VST 模块 SDK

【中文标题】VST SDK & VST 模块 SDK【英文标题】:VST SDK & VST Module SDK 【发布时间】:2012-04-30 12:30:44 【问题描述】:

我想创建一个带有编辑器的面向模式的 VST MIDI 插件(没有音频处理,只是一个带有强大的模式编辑器和随机发生器的 UI 编辑器)。

我已经阅读了 可怕的 VST 和 VST 模块 SDK 文档。我希望你们中的一些人能回答我的问题:

我说对了吗:VST SDK 仅用于音频效果和乐器,而 VST 模块 SDK 仅用于 MIDI 效果? 没有一个 VST 模块 SDK 的示例正在运行(它们需要 VSTGUI,它不在 VST 模块 SDK 中。我尝试使用以下 VSTUI:SDK 2.4、SDK 3.5.1 或 VSTGUI.sf,但我可以' t 编译它。它最终会出现大量错误。

那里有人可以为我指明正确的方向吗? 谢谢

【问题讨论】:

【参考方案1】:

是的,VSTGUI 源代码一团糟。几年前它经历了一次非常糟糕的重写,VST SDK 也是如此。顺便说一句,术语“模块 SDK”基本上是指 VST SDK 的相同方式。从版本 3 开始,该术语可能更频繁地使用,因为 VST3 插件在这方面进行了扩展。

无论如何,回到你的项目。如果您不打算进行音频处理,我建议您将插件实现为发送 MIDI 的乐器。如果您使用awesome Juce framework,您可以很容易地完成此操作,以及一个不错的 GUI 工具包和设计工具。

【讨论】:

感谢您的快速回答。好吧,在开发者下载部分有 3 个下载:VST SDK 3.5.1、VST SDK 2.4 和 VST 模块 SDK。 VST 2.4 和 Module SDK 都很老了。我和你有同样的想法。如果我将它实现为 VST3 插件(继承自 AudioEffect 类或组件类),则该插件不会显示为 MIDI 插件。相反,它显示为音频效果类。对此有任何提示吗? VST 3 SDK 中没有任何内容可以创建纯 MIDI 插件(VST 模块 SDK 对此提供支持)。 你们必须停止说“很棒的 Juce 框架”,因为它不是那么好,至少现在不是。去那里看看他们今天遇到的问题,你就会明白为什么你仍然想自己写几乎所有的东西。 @Morgan,抱歉,我不同意。与一些坚持自己滚动一切的专业音频公司合作后,Juce 是一个更好的选择。与其传播 FUD,不如提供(或制造)一个合适的替代方案? @NikReiman 为什么要做得更好,因为当内核中的一切都发生变化时,它也会以一团糟而告终,并且拥有许可证的人最终或多或少地放弃了这艘船。一直在发生使所有旧的源代码变得毫无用处,是的,我已经并且正在使用各种框架,这将是一场无休止的辩论。我只是说人们必须在这里放下耶稣的标志。 @Morgan 很有趣,您可以为 VST SDK 本身提出完全相同的论点(并且更加强调疯狂的许可、不良所有权、混乱的代码等)。我想那时写VST根本没有意义:P

以上是关于VST实例绘制VST的主要内容,如果未能解决你的问题,请参考以下文章

如何在代码中实例化 Vst3 插件?对于 vst3 主机应用程序

VST实例编辑

VST实例(10) hint(提示)

vst实例创建编辑器

VST实例拖拽(drag&drop)

VST SDK & VST 模块 SDK