跳转到内容

Aros/开发人员/Zune/类

来自维基教科书,开放世界中的开放书籍
Aros 维基教科书的导航栏
Aros 用户
Aros 用户文档
Aros 用户常见问题解答
Aros 用户应用程序
Aros 用户 DOS Shell
Aros/用户/AmigaLegacy
Aros 开发人员文档
Aros 开发人员文档
从 AmigaOS/SDL 移植软件
面向 Zune 初学者
Zune .MUI 类
面向 SDL 初学者
Aros 开发人员构建系统
特定平台
Aros x86 完整系统 HCL
Aros x86 音频/视频支持
Aros x86 网络支持
Aros Intel AMD x86 安装
Aros 存储支持 IDE SATA 等
Aros Poseidon USB 支持
x86-64 支持
Motorola 68k Amiga 支持
Linux 和 FreeBSD 支持
Windows Mingw 和 MacOSX 支持
Android 支持
Arm Raspberry Pi 支持
PPC Power Architecture
杂项
Aros 公共许可证
神奇用户界面 MUI

Mui 原始类 或此处 由尾部的 .mui 标识,例如 List、String 等

MUI(Zune)替代类 MCC 后来出现,其中包括 Nlist、BetterString 等,一些开发人员对此感到不满。

请阅读 autodocs/MUI_Application.doc/MUIM_Application_NewInput,其中包含一个完整的完整主循环示例。MUI 程序有一个主循环,但在理想的应用程序中,该循环是空的。主循环以及钩子已经成为过去,但向后兼容性仍然存在。

新方法因此,如今,为了处理来自按钮、滑块等的通知,您对 Application.mui、Window.mui 或 <您选择的组之一>.mui 进行子类化,在其中定义您自己的私有方法,并在按钮上设置通知以调用这些方法。这样,您就可以保持一个整洁的内部结构,而不是将所有内容都放在一个巨大的 return id switch 语句中。

方法没有 TRUE 或 FALSE 状态,也没有其他定义的状态,它们只是函数调用(有点像)。唯一的方法是子类化技术并重载该方法。然后,您可以做任何您想做的事情。自定义类是您的方法。

要定义您自己的私有方法和属性 ID,您可以从 TAG_USER 开始。

在此处阅读更多信息此处

旧方法使用 MUI,您也可以调用钩子来避免创建子类,但只有属性更改才会导致操作。

  • 首先设置 Application 和 Window 类的信息。
  • 使用水平组 (HGroup) 或垂直组 (VGroup) 将对象(按钮、滑块、目录列表器等)塞入其中。对象不会直接放置到一些固定位置,而是分组在特殊的容器中,这些容器随后会被动态显示和定位。
  • 使用通知在对象更改(按下、滑动等)时执行某些操作
  • 完成后或结束应用程序时释放它们

宏在 Zune 界面编程中发挥作用。Get 和 Xget 可以替换 GetAttrs,Set 和 Xset 类似地替换 SetAttrs。

当您阅读 mui autodocs 时,在函数名称后面有一个字段,其中包含 [ISG],有时也包含 [ISGN]

这表明您可以对该标签执行什么操作。

I = Init
S = SetAttr can be used
G = GetAttr can be used
N = Supports Notify

因此,如果您看到 [I.G],则意味着您可以在 Init 时使用该标签,并在其上使用 GetAttr。

MUI Zune 基础类

[编辑 | 编辑源代码]
连接到 Zune NOTIFY.mui 类的 BOOPSI 根类
Application.mui Window.mui Family.mui Area.mui
Aboutmui Menustrip Rectangle
Menu Balance
Menulist Image
Menubar
Bitmap
Text
Gadget
Gauge
Scale
Colorfield
List
Numeric
Pendisplay
Group

封装是您在所有 MUI 类中拥有的东西。例如,要使用列表视图,您需要为此小工具定义一个明确的接口,所有实现细节都封装在类中(如私有变量等)。

您将在高级应用程序中执行类似的操作。找到所有子系统,并将它们实现为具有封装在模块中的接口和实现细节的“隔离”模块,从外部不可见。

通过子类化实现继承

多态性

子类化类

好的源代码示例 SnakeeList

应用程序

[编辑 | 编辑源代码]
在此处阅读更多信息 以及 此处有关应用程序类的信息

MUI_NewObject(MUIC_Application, ,etc) 通常被宏 ApplicationObject 等替换。

对窗口或应用程序类进行子类化时,根本没有 MUIM_Setup/Cleanup 方法。

如果您想创建一个 gui,其中所有内容都是由自定义类构成的(至少是外部内容,即应用程序和窗口),您可以像往常一样定义所有类,然后使用单个 newobject() 调用实例化您的应用程序。在分配(在 OM_NEW 内)时向组/窗口/应用程序添加元素没有问题。

Gui 设计

MUI_NewObject(MUIC_Window, ,etc) 通常简化为宏 WindowObject 等,但在子窗口中仍然可以使用...

执行此操作的方法是在您的子类之一中实现一个方法(MUIC_Window 或窗口的 Root MUIC_Group 始终是安全的选项),并让 MUIA_Window_? 通知调用它。

为了记住位置,您必须在处置 Zune Application 对象之前关闭窗口(将 MUIA_Window_Open 设置为 false)。

Morphos List 子类

MUI_NewObject(MUIC_Group, ,etc) 通常被重写为宏 <Group>GroupObject 等。

然后是类创建

TheClass = MUI_CreateCustomClass (NULL, supername, NULL, sizeof (MyObjectData), dispatcher);
  if (!(mcc = MUI_CreateCustomClass(NULL,MUIC_Area,NULL,sizeof(struct NewClass_Data),NewClass_Dispatcher)))
  {
    printf("Cannot create custom class.\n");
    return(0);
  }

从其他类型的对象继承可以吗?可以,对滑块类进行子类化以重载 MUIM_Numeric_Stringify 方法。

在构建 GUI 时,如何检查 MUI MCC 的最低版本?[...] 你最好的机会是自定义类编写者重载了 MUIA_Version/Revision。

做事情

[编辑 | 编辑源代码]

这里有一种在方法中访问它的方法

LONG AnyMethod (Class *cl, Object *obj, Msg msg)
{
struct MyObjectData *data = INST_DATA(cl,obj);

/*...*/

if (!strcmp ("Amiga", data->Pointer)) DoSomething();

/*...*/
}

为对象数据结构分配的内存由 MUI 在对象析构函数中自动释放,你无需做任何操作。

struct MyObjectData *data = (MyObjectData *)INST_DATA(cl, obj);

调度器

[编辑 | 编辑源代码]

然后,在你的调度器子程序中,你可以编写类似于 case MUIM_NList_ContextMenuBuild then MyOwnContextMenuBuild(cl,obj,msg); 的代码,然后编写一个子程序 MyOwnContextMenuBuild,在调用此方法时执行你的类需要执行的操作。

你的子类中的每个对象都会在其对象 "结构" 中添加自己的数据区域。也称为数据实例化。这是你自己的 var 区域,专属于对象,在 MUI_CreateCustomClass() 调用中指定的大小,但不要使用过时的 MUI_GetClass() 和 MakeClass() 配对。参见 MUI:Developer/C/Examples 目录中的 Class2.c 示例。

重载 类方法是当你需要添加一些类特性或使用一些特殊行为时使用的主要且最佳的设计。在 MUI C 版本中,这是通过创建一个新的 MCC(MUI 自定义类)和一个调度器例程来完成的,该例程在对该 MCC 的实例调用 DoMethod() 时捕获传入的 BOOPSI 消息。

如何知道超类的属性何时改变,而不使用 Notify?是的,只需重载 OM_SET。大多数(如果不是全部)对 OM_SET 的调用都是使用在堆栈上分配的临时标签列表完成的,因此它无论如何都会丢失...

如果你需要为每个对象单独使用此指针,则应将其放置在对象数据结构中。

struct MyObjectData
{
char *Pointer;
};

标签列表或方法结构应保持完好无损,除非有说明。如果 MUI 或第三方 mcc 这样做,它们就坏了... MUI 触碰的文档化方法结构的示例是 MUIM_Draw 和 MUIM_AskMinMax...

如果尺寸发生变化,MUI 将在你的对象上调用 MUIM_Hide、MUIM_Show。因此无需在 MUIM_Draw 中检查此项。顺便说一下,MUIM_Draw 总是出于某种原因被调用,因此没有理由让你在这里省略重绘。

ULONG NewList_New(struct IClass *cl , Object *obj, Msg msg)
{
    return 0;
}

ULONG NewList_Set(struct IClass *cl , Object *obj, Msg msg)
{

    return(DoSuperMethodA(cl, obj, msg));
}

ULONG NewList_Get(struct IClass *cl, Object *obj, Msg msg)
{

    return(DoSuperMethodA(cl, obj, msg));
}

应用程序和窗口

[编辑 | 编辑源代码]

你如何随时获得指向活动窗口对象的指针?通常,你应该在应用程序窗口列表中搜索 MUIA_Window_Active。可以创建 MUIC_Window 子类并拦截 MUIA_Window_Active,并为此创建你的 API。另一方面,你可以在此标签上设置通知,如果窗口收到通知,你将知道它并设置内存中的某个字段以指向窗口或类似内容。

MUIA_Window_Screen 用于你自己的屏幕,并试图完全控制窗口大小。当你没有为 WindowObject 指定窗口 ID(MUIA_Window_ID)时,设置 MUIA_Window_Width 和 MUIA_Window_Height 总是有效的。如果你指定了此 ID,则高度和宽度将由系统自动设置,并会在下次运行应用程序时被记住。

     app = ApplicationObject,
         MUIA_Application_Title, (IPTR)"KeyShow",
         MUIA_Application_Version, (IPTR)"$VER: KeyShow 1.0 (24.02.2012)",
         MUIA_Application_Copyright, (IPTR)_(MSG_AppCopyright),
         MUIA_Application_Author, (IPTR)"The AROS Development Team",
         MUIA_Application_Description, (IPTR)_(MSG_AppDescription),
         MUIA_Application_Base, (IPTR)"KEYSHOW",
 
         SubWindow, (IPTR)(win = WindowObject,
             MUIA_Window_Title, (IPTR)_(MSG_WI_TITLE),
             MUIA_Window_ID, MAKE_ID('K','S','W','N'),
             WindowContents, (IPTR)KeyboardGroupObject,
             End,
         End),
     End;
 
     if (app == NULL)
/*
    Copyright © 2002, The AROS Development Team.
    All rights reserved.

    $Id: dtpic.c 30792 2009-03-07 22:40:04Z neil $
*/

#include <dos/dos.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/muimaster.h>

#include <libraries/mui.h>

struct Library *MUIMasterBase;

Object *app;

int main(void)
{
    Object *wnd;
    
    MUIMasterBase = (struct Library*)OpenLibrary("muimaster.library",0);

    app = ApplicationObject,
   	SubWindow, wnd = WindowObject,
    	    MUIA_Window_Title, "dtpic test",
	    MUIA_Window_Activate, TRUE,

    	    WindowContents, VGroup,
    	    	Child, MUI_NewObject("Dtpic.mui",MUIA_Dtpic_Name,"SYS:System/Images/AROS.png",TAG_DONE),
		End,
	    End,
	End;

    if (app)
    {
	ULONG sigs = 0;

	DoMethod
        (
            wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, (IPTR) app, 
            2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit
        );

	set(wnd,MUIA_Window_Open,TRUE);

	while (DoMethod(app, MUIM_Application_NewInput, (IPTR) &sigs) != MUIV_Application_ReturnID_Quit)
	{
	    if (sigs)
	    {
		sigs = Wait(sigs | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
		if (sigs & SIGBREAKF_CTRL_C) break;
		if (sigs & SIGBREAKF_CTRL_D) break;
	    }
	}

	MUI_Object(app);
    }

    CloseLibrary(MUIMasterBase);
    
    return 0;
}

你必须在打开窗口之前将窗口 OM_ADDMEMBER 到应用程序,并且如果你想在窗口中显示区域对象(成为 GUI 的一部分),你必须将区域对象 OM_ADDMEMBER 到组对象(在一个 MUIM_Group_InitChange/ExitCHange 对中)。Mui Dev 文档有一节关于动态窗口(动态对象链接/窗口),其中包含有关动态窗口创建的详细文档。

但是你可以创建一个自定义类,并通过查找传入的方法来获得通知。重载 MUIM_Setup 可能是一个好主意。你可以子类化你的窗口,并在 MUIM_Setup 中放置屏幕更改检测。例如,在每次 MUIM_Setup 中,你都可以将屏幕指针记住在对象数据中的某个地方,将其与先前值进行比较,如果屏幕已更改,则执行某些操作。在 MUIM_Setup 后使用 _app(obj)。

你可以在所有对象放置的 MUIC_Group 的子类中进行操作... 当你在 MUIM_Setup 中检测到 _screen() 更改时,你将 MUIA_Window_CloseRequest 设置为 TRUE... 如果你的应用程序在 WB 屏幕上运行,用户可以随时更改 WB 屏幕分辨率/深度。用户可以随时从自定义屏幕数据库更改你的屏幕。需要考虑的另一件事是来自 Exchange 或 ARexx 的最小化。你_必须_对屏幕更改做出反应。

然后你应该将 MUIM_Application_Save 放置在你的主循环之后。

重载 MUIM_Window_Snapshot,并在其中添加一些代码,这些代码会保存首选项,这样就可以在用户选择窗口边框上的快照图标时保存,而不仅仅是在程序结束时保存。如果你确实想在快照时保存,则必须使用 CreateCustomClass() 创建一个新类,该类必须是 MUIC_Window 的子类。在这个子类的调度器中,你必须在调度器收到 MUIM_Window_Snapshot 方法时调用你自己的代码。然后你必须更改应用程序创建代码:你必须用你的窗口子类的对象创建(Intuition.NewObject())来替换每个窗口创建。

在处理窗口时似乎存在一个普遍问题:你_不能_在窗口处理方法中引用应用程序对象!为什么?因为在处理窗口之前,你将它从应用程序中取消链接(OM_REMMEMBER)。在那之后,窗口不再属于应用程序,使用 _app(obj) 是非法的。在 OM_NEW 期间,你无法使用 _app(obj),OM_DISPOSE 也是如此。

在 setup/cleanup 方法(在 DoSuperMethod 之前或之后)中的任何位置使用 _app(obj) 都可以。事实上,在 new/dispose 和 setup/cleanup 之间还有一个层,对象可以在其中了解其应用程序上下文。但是,该层尚未通过方法公开提供。

MUIA_Window_IsSubWindow 正是为此而设计的(跳过 OM_REMMEMBER 和 OM_DISPOSE)。但是,这不是解决应用程序对象中 "全局" 窗口列表带来的所有问题的方案。窗口类可能应该能够拥有更多子窗口。

我们如何从我的 MUI 对象中获取实际的窗口?

struct Window *win;
DoMethod(obj,MUIA_Window,&win);

MUIA_Window 是一个属性。你可以通过从 Intuition 中调用 GetAttr() 来读取属性

GetAttr(MUIA_Window, obj, &x);

还有一些警告

  • 只有在窗口打开时,MUIA_Window 才是有效的
  • MUIA_Window 是一个区域类标签。对窗口对象使用 MUIA_Window_Window。

要对 MUI 窗口调用 ChangeWindowBox。只需注意窗口当前是打开的(MUIA_Window_Window!=NULL)需要屏幕,你可以随时获取 MUIA_Window_Window 并像使用其他 Intuition 窗口一样使用 window->WScreen 等。

MUIM_Application_PushMethod

因此你想要先退出对象上下文,这可以通过 MUIM_Application_PushMethod 很容易地完成。

/* From your mail window */
DoMethod(_app(obj), MUIM_Application_PushMethod, _app(obj), 2,
MUIM_MyApplication_RemoveObject, obj);

/* From your application subclass */
case MUIM_MyApplication_RemoveObject:
{
DoMethod(obj, OM_REMMEMBER, msg->Obj);
MUI_DisposeObject(msg->Obj);
}
break;

基本上有一个渲染任务,它执行大量计算并渲染到一个离屏 rastport。当它完成一帧时,它将一个标志(Drawn)设置为 FALSE,释放一个信号量,并执行 PushMethod。

主程序在它的事件循环中耐心地等待着,在某个时候会被 PushMethod 唤醒,这会触发自定义类在内部执行 MUI_Redraw(),进而获取信号量,将离屏位图复制到窗口,将 Drawn 设置为 TRUE,并释放信号量。然后它回到睡眠状态。

同时,渲染子任务执行了 ObtainSemaphore。当它获取到它时,它会检查 Drawn 是否为 TRUE。如果是,它可以继续,因为这意味着主任务已成功复制位图。否则,它会释放它,进行短暂的 Delay,然后再次尝试,以尝试为主任务提供时间来抢占信号量并完成它的工作。

因此,信号量实际上是在保护离屏 rastport(以及 Drawn 标志) - 两个任务都无法访问或更改它,除非先获取信号量,而标志用于告诉绘制任务主任务是否有机会完成它的工作。大多数时候(即几乎总是)主任务确实设法立即抢占信号量,因此绘制任务无法太快地抢回它。如果主任务完成得很快,那么当绘制任务尝试获取信号量时,它会立即成功,因此没有损失。

但是,PushMethod 不应该过度重载,对于进程间通信,建议使用私有消息端口来处理更密集的任务。将其用作唤醒主任务并使其向自定义类发送 MUI_Redraw 的信号机制,并且每次只发送一个(尽管每秒有 30-60 个)。在这些情况下,从未遇到过任何问题。

struct SignalSemaphore lock_AddEntry_Sem;
...
InitSemaphore(&lock_AddEntry_Sem);
...
while(something){
...
   ObtainSemaphore(lock_AddEntry_Sem);     // Grab the semaphore
   while (lock_AddEntry){                  // Main task completed its job?
      ReleaseSemaphore(lock_AddEntry_Sem); // No, release semaphore
      Delay(1);                            // Wait a bit
      ObtainSemaphore(lock_AddEntry_Sem);  // Try again
   }
...
   lock_AddEntry = TRUE;                   // Set flag
   ReleaseSemaphore(lock_AddEntry_Sem);    // Give CPU back to main task
...
}

MsgPorts 速度较慢。信号量在任何类似 AmigaOS 的系统中都更适合使用。

除非返回 MUI_EventHandlerRC_Eat,否则 MUIM_HandleEvent 将为每个事件处理程序节点调用。如果事件未被 MUIM_HandleEvent 吞食,则 MUIM_HandleInput 将为活动对象调用。

是否应该使用 EventHandler 而不是 request?为了避免即使我的对象不是活动对象也能收到事件?是的 - 事件处理程序会尊重诸如活动对象和默认对象、优先级等属性。HotkeyString 是 BetterString 的子类。它添加了一个新的事件处理程序,具有更高的优先级,因此在它的超类之前获得事件,而对于另一种方法(可以重写 MUIM_HandleInput,但这只是一个例子...)则不会出现这种情况。

事件处理程序还允许你吞噬输入,这是 IDCMP-requesting 不可能做到的另一件事。这意味着许多对象(使用旧方法)只有在它们是活动对象或默认对象时才会解释输入,这在 IProbe 中很糟糕,因为我希望 HTMLview 对向上/向下箭头做出反应,即使 URL 字符串处于活动状态 - 据我所知,这只有通过事件处理程序才能实现。

正确的方法是知道当前活动窗口(我之前跟踪的是 IDCMP_ACTIVEWINDOW/IDCMP_INACTIVEWINDOW)。使用 MUI 的正确方法是什么,才能知道窗口已变为活动窗口?你可以尝试设置一个调度器,将所需的动作添加到事件处理程序中。

struct your_data
{
struct MUI_EventHandlerNode ehnode;
};

ULONG yoursetup(struct IClass *cl, Object *obj, Msg msg)
{
struct your_data *data = (struct your_data *)INST_DATA(cl, obj);

if (!DoSuperMethodA(cl, obj, msg))
return(FALSE);

data->ehnode.ehn_Object = obj;
data->ehnode.ehn_Class = cl;
data->ehnode.ehn_Events = IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW;

DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);

return(TRUE);
}

添加一个类似于以下内容的清理调度器

ULONG yourcleanup(struct IClass *cl, Object *obj, struct MUIP_HandleInput *msg)
{
struct your_data *data = (struct your_data *)INST_DATA(cl, obj);

DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
return(DoSuperMethodA(cl,obj,msg));
}

为 MUIM_HandleEvent 添加一个调度器,并处理你想要的事件,例如

ULONG yourhandler(struct IClass *cl, Object *obj, struct MUIP_HandleInput *msg)
{
struct your_data *data = (struct your_data *)INST_DATA(cl, obj);

if (msg->imsg)
{
case IDCMP_ACTIVEWINDOW:
// Do what you want here
break;

case IDCMP_INACTIVEWINDOW:
// Do what you want...
break;
}

return(DoSuperMethodA(cl, obj, (Msg)msg));

}

或者你可以尝试安装一个事件监听器,每次 MUIA_Window_Activate 发生更改时都会触发。

即使窗口不活动,也能够将鼠标坐标和按键输入到我的应用程序中。你可以轮询直觉库,并在任何时间读取鼠标坐标。如果你的应用程序想要一直监控它,中断例程将是最佳解决方案...(可能可以使用其他库)。

除非你明确使用 MUIM_Application_InputBuffered,否则所有内容都是单线程的。没有函数会中断以处理信号。更好的方法是将 MUI 接口处理卸载到一个单独的任务中,并通过信号与网络任务进行通信吗?这至少可以解决上面提到的问题。STRICQ 使用 MUI,并设置为处理任意数量的同步套接字,包括 TCP 和 UDP。首先创建另一个窗口,然后调用 MUIM_Application_InputBuffered(即使你应该尽量避免这样做),然后执行 PushMethod。如果必须使用 InputBuffered 来处理其他动作,我该怎么办?想出一个设计模式来避免在你程序中间进行这种讨厌的输入探测。为此目的创建一个应用程序类的子类,你可以在其中调用一个方法,并使用要删除的对象作为参数,然后应用程序子类会存储指向该对象的指针,并在 MUIM_Application_Input 返回后将其删除(嵌套计数器告诉我,没有其他递归调用 MUIM_Application_Method)。请记住,MUIM_PushMethod 不是安全的,因为它可能会失败(例如内存不足),然后你的对象不会被删除(即内存泄漏)。使用应用程序类的子类的解决方案是安全的,因为没有必要通过将它添加到“内部”Group 类中来分配用于指向该对象的指针的内存。

图标化

[edit | edit source]
#ifdef __amigaos4__
    MUIA_Application_DiskObject , diskobject = GetDiskObject(_ProgramName),
    #endif

MUIA_Application_DiskObject,GetDiskObject("PROGDIR:mp3player"),

其中 PROGDIR:mp3player 是你的应用程序的名称。注意,你以这种方式泄漏了磁盘对象。请确保将其分配给指针,并在应用程序结束之后调用 FreeDiskObject..

struct DiskObject *my_app_icon;
MUIA_Application_DiskObject,my_app_icon=GetDiskObject("PROGDIR:zamp"),

ULONG iconified=0;
get(application, MUIA_Application_Iconified, &iconified);
if( !iconified)

如何从你自己的程序中执行 arexx 脚本,就好像它是从你程序的 arexx 端口运行的一样。一个应用程序子类,它添加一个名为 MUIM_Application_RunScript 的方法,只需使用脚本名称及其参数调用此方法,它就会使用你的(MUI)端口作为主机启动,并确保你的程序在脚本完成之前不会退出。

ULONG ListWindows( Object *application )
{
ULONG windows = 0;
struct MinList *windowlist;
windowlist = (struct MinList *) xget( application,
MUIA_Application_WindowList );
if( windowlist && !IsListEmpty( (struct List *) windowlist ) )
{
Object *object, *objectstate = (Object *) windowlist->mlh_Head;
while( object = NextObject( &objectstate ) )
{
Printf( "Object 0x%08lx is %swindow.\n",
object,
IsWindow( object ) ? "" : "not " );
windows++;
}
}
return( windows );
}

你可以使用与以下代码类似的代码检查对象类是 MUIC_Window 的类还是子类

BOOL IsWindow( Object *object )
{
struct IClass *windowclass = MUI_GetClass( MUIC_Window );
struct IClass *class;
for( class = OCLASS( object ); class; class = class->cl_Super )
if( class == windowclass )
return( TRUE );
return( FALSE );
}

外部输入

[edit | edit source]

 MUIM_Application_AddInputHandler(struct( MUI_InputHandlerNode ) 在你的类的 MUIM_Setup 和 MUIM_Cleanup 方法中(不是子类?)。

使用 MUIM_Application_RemInputHandler 删除。

已过时的钩子 如果在由通知调用的钩子内调用 MUI_DisposeObject() 来释放通知所附加的对象,这样做安全吗?这样做不安全。钩子内容不会被释放,因为在从钩子返回之后,仍然需要执行来自调用类的某个返回值。

MUIM_Application_AboutMUI 
MUIM_Application_AddInputHandler 
MUIM_Application_CheckRefresh 
MUIM_Application_InputBuffered 
MUIM_Application_Load 
MUIM_Application_NewInput (replaces old Input) 
MUIM_Application_OpenConfigWindow 
MUIM_Application_PushMethod 
MUIM_Application_RemInputHandler 
MUIM_Application_ReturnID 
MUIM_Application_Save 
MUIM_Application_SetConfigItem  
MUIM_Application_ShowHelp        
MUIA_Application_Active 
MUIA_Application_Author 
MUIA_Application_Base 
MUIA_Application_Broker 
MUIA_Application_BrokerHook 
MUIA_Application_BrokerPort 
MUIA_Application_BrokerPri 
MUIA_Application_Commands 
MUIA_Application_Copyright 
MUIA_Application_Description 
MUIA_Application_DiskObject 
MUIA_Application_DoubleStart 
MUIA_Application_DropObject 
MUIA_Application_ForceQuit 
MUIA_Application_HelpFile 
MUIA_Application_Iconified 
MUIA_Application_MenuAction 
MUIA_Application_MenuHelp 
MUIA_Application_Menustrip 
MUIA_Application_RexxHook 
MUIA_Application_RexxMsg 
MUIA_Application_RexxString 
MUIA_Application_SingleTask 
MUIA_Application_Sleep 
MUIA_Application_Title 
MUIA_Application_UseCommodities 
MUIA_Application_UsedClasses 
MUIA_Application_UseRexx 
MUIA_Application_Version 
MUIA_Application_Window 
MUIA_Application_WindowList 
MUIM_Window_AddEventHandler 
MUIM_Window_Cleanup 
MUIM_Window_RemEventHandler 
MUIM_Window_ScreenToBack 
MUIM_Window_ScreenToFront   
MUIM_Window_Setup 
MUIM_Window_Snapshot 
MUIM_Window_ToBack 
MUIM_Window_ToFront 
MUIA_Window_Activate 
MUIA_Window_ActiveObject 
MUIA_Window_AltHeight 
MUIA_Window_AltLeftEdge 
MUIA_Window_AltTopEdge 
MUIA_Window_AltWidth 
MUIA_Window_AppWindow 
MUIA_Window_Backdrop 
MUIA_Window_Borderless 
MUIA_Window_CloseGadget 
MUIA_Window_CloseRequest 
MUIA_Window_DefaultObject 
MUIA_Window_DepthGadget 
MUIA_Window_DisableKeys 
MUIA_Window_DragBar 
MUIA_Window_FancyDrawing 
MUIA_Window_Height 
MUIA_Window_ID 
MUIA_Window_InputEvent 
MUIA_Window_IsSubWindow 
MUIA_Window_LeftEdge 
MUIA_Window_MenuAction 
MUIA_Window_Menustrip 
MUIA_Window_MouseObject 
MUIA_Window_NeedsMouseObject 
MUIA_Window_NoMenus 
MUIA_Window_Open 
MUIA_Window_PublicScreen 
MUIA_Window_RefWindow 
MUIA_Window_RootObject 
MUIA_Window_Screen 
MUIA_Window_ScreenTitle 
MUIA_Window_SizeGadget 
MUIA_Window_SizeRight 
MUIA_Window_Sleep 
MUIA_Window_Title 
MUIA_Window_TopEdge 
MUIA_Window_UseBottomBorderScroller 
MUIA_Window_UseLeftBorderScroller 
MUIA_Window_UseRightBorderScroller 
MUIA_Window_Width 
MUIA_Window_Window 

对象

[edit | edit source]

DoMethod( object1, method, attribute, value, object2, parameter_number, method2, attribute2, value2 [,...])

  • MUIM_Application_NewInput
  • MUIM_Window_
  • MUIM_CallHook MUIM_FindUData MUIM_GetUData MUIM_SetUData
  • MUIM_KillNotify MUIM_NoNotifySet MUIM_Notify
  • MUIM_Set MUIM_MultiSet MUIM_SetAsString
  • MUIM_List_InsertSingle

当创建一个和销毁一个 Zune 对象时,会调用几个方法。

OM_NEW
MUIM_Setup
MUIM_AskMinMax
[ window is opened here ]
MUIM_Show
MUIM_Draw
MUIM_Hide
[ window is closed here ]
MUIM_Cleanup
OM_DISPOSE

如果某些东西只在 setup 和 cleanup 之间有效,这意味着你可以在 setup 方法中第一次使用它,并且不允许你在 cleanup 之后使用它。

如果你想管理一组不可见的对象,MUIC_Family 类可能会有所帮助。

需要知道对象的大小,而程序在 MUIM_GroupInitChange 和 MUIM_GroupExitChange 之间。简单地询问 MUIA_Width 和 MUIA_Height 会返回 0。有人有主意吗?在再次调用 ExitChange 之前,宽度/高度是无效的。但是,如果你需要知道对象尺寸,子类化可能是最佳方法。你可以使用 _width()/_height() 宏获取对象尺寸。

对象无法区分 OM_SET 是通过 SetAttr() 还是通过 MUIM_MultiSet 调用。一些标准 MUI 类确实会修改传递给它们的标签列表。一个很好的例子是 Group 类;它将某些标签设置为 TAG_IGNORE,因为它们要么不能转发给子级,要么不应该由它的超类(Area)处理。

如何在应用程序中添加一个选定图像,以便使用不同的图像来表示正常状态和选定状态?大多数人使用带有 PageMode 设置的 Group,因此当 Group 被按下时,它会简单地切换显示的页面,并且每个页面都会显示其上所需的图像。

通知

[edit | edit source]
Morphos 通知

基本上,MUI 不使用 BOOPSI 的通知系统。通知以透明的方式发生;你唯一需要做的就是将方法传递给你的超类,并且你应该始终这样做 - 你不需要使用非 MUI BOOPSI 类所使用的方法。

你可以在你自定义类的每个属性上放置通知。假设你的类是从 MUIC_Notify 派生的。然后,MUI 会在你设置属性时自动执行通知。

你可以使用 MUIM_Notify 方法将通知放置在任何类(或其祖先)的任何(公共)属性上。这些通知可以在任何时间从任何地方放置。

你只需要使用 set() 来更改对象的属性,并在你的 set 方法处理程序中添加

 return (DoSuperMethodA(cl, obj, msg)); 

在最后。这将把 OM_SET 传递到类层次结构中,传递给 Notify.mui,然后它会执行通知。当然,另一件事是,无论何时你想更改一个值,都要始终使用 set(),而不是直接分配它。只应在 OM_SET 方法中直接分配它。

当其他类在你的某个属性上放置一个通知时,并且你的属性使用 set()(或 OM_SET)更改时,当它执行 DoSuperMethod() 调用时,OM_SET 最终会到达所有 MUI 类的根类 - Notify.mui。它会保留一个要执行的通知列表。

    /* This is setting up a notification on the MUIA_Robot_FrameRate * attribute */ 
    DoMethod(MyObj,
            MUIM_Notify, MUIA_Robot_FrameRate, MUIV_EveryTime,
            FrameCntObj,
            4,
            MUIM_SetAsString, MUIA_Text_Contents, MUIX_R"%ld", MUIV_TriggerValue
    );

...

    /* This is setting the frame rate (actually done within the class
     * itself -- ie. I use set() rather than just changing the value
     * directly in case there are notifications on it. */
    set(obj, MUIA_Robot_FrameRate, data->framecnt - data->lastframecnt);

...

/* This is the relevant part of my custom class's OM_SET method
 * handler. */
static ULONG mSet(struct IClass * cl, Object * obj, Msg msg)
{
    struct MyData *data = INST_DATA(cl, obj);
    struct TagItem *tags, *tag;

    for (tags = ((struct opSet *) msg)->ops_AttrList; tag = NextTagItem(&tags);)
    {
        switch (tag->ti_Tag) {
...
          case MUIA_Robot_FrameRate:    data->framerate = (ULONG) tag->ti_Data;
                                        break;
...
        }
    }

    return(DoSuperMethodA(cl, obj, msg));
}

如果你有一个属性 MUIA_Xxx_Yyy,它可以读写且可通知,并且被 mGet()(你的 OM_GET 方法)识别。在内部,它从 data->Yyy 读取。此外,假设你有一个私有属性 MUIA_Xxx_YyyP(最好给它一个与你类中其他属性完全不同的数值),它被 mSet() 识别,并写入 data->Yyy。然而,mSet() *不* 识别 MUIA_Xxx_Yyy。mSet() 中的 switch 语句中识别 MUIA_Xxx_YyyP 的代码,除了写入 data->Yyy 之外,还会将 tag->ti_Tag 更改为 MUIA_Xxx_Yyy。然后,当执行 DoSuperMethodA() 调用时,Notify 类会识别已更改的属性为 MUIA_Xxx_Yyy,并正确执行通知。

假设你的类使用自定义属性 MUIA_HHH_MyAttr。其他对象可以请求 MUI 在此属性被 set() 设置为给定值时通知它们,例如你可能会有类似以下内容

DoMethod(obj1,MUIM_Notify,MUIA_HHH_MyAttr,32,obj2,1,MUIM_MyObj_Changed);

这里,对象 obj2 请求在 obj1 的属性 MUIA_HHH_MyAttr 被 set() 设置为 32 时使用方法 MUIM_MyObj_Changed 通知它们。

Child, Label2("允许重复:"), Child, ck6 = CheckMark(TRUE),

DoMethod(ck6, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, app, 2, MUIM_Application_ReturnID, ACT_CK6);

关于此错误令人困惑的是,它只会影响 CheckMark(TRUE) 对象(或者如果你使用 MUIM_Application_Load 来恢复复选框的状态,那么那些被设置为 TRUE 的复选框会表现出相同的问题)。

自动文档指出你只需要添加复选框和字符串(成对),即使在“不可见”空间中也是如此。你需要这个字符串,因为复选框的自动字符串只能放置在左侧(这将是不直观的)。

Object *MakeCheck(BYTE state, char *label)
{
  return ImageObject,
           ImageButtonFrame,
           MUIA_Text_Contents, label,
           MUIA_InputMode   , MUIV_InputMode_Toggle,
           MUIA_Image_Spec  , MUII_CheckMark,
           MUIA_Background  , MUII_ButtonBack,
           MUIA_ShowSelState, state,
           MUIA_CycleChain  , TRUE,
         End;
}
DoMethod(timerobj,MUIM_Notify,MA_Timer_Seconds,MUIV_EveryTime,obj,2,MM_Clock_Seconds,MUIV_TriggerValue);

这应该在 MA_Timer_Seconds 发生更改时每次调用 MM_Clock_Seconds。

WaitIO(data->req);
CurrentTime(&raw,&micros);
today = raw%86400;
SetAttrs(obj,MA_Timer_Seconds,today%60,TAG_DONE);

通知没有发生

data->seconds = today%60+30;
data->minutes = (today%3600)/60;
data->hours = today/3600;
data->req->tr_node.io_Command = TR_ADDREQUEST;
data->req->tr_time.tv_secs = 1;
data->req->tr_time.tv_micro = 0;
SendIO((struct IORequest *)data->req); 

timerobj 的 OM_GET

case MA_Timer_Seconds:
 *msg->opg_Storage = data->seconds;
return TRUE; 

类没有 OM_SET,但你必须实现 OM_SET 来通知。我不会为此类事件使用 MUI 通知,因为由于 BOOPSI 延迟。定时器确实有效(通过在时钟类的每个 MUIM_Draw 中获取 MA_Timer_Seconds 来测试,但 MM_Clock_Seconds 从未被调用)。

SetAttrs(NULL, ... 理论上你不必这样做,因为 SetAttrsA() 只是 DoMethodA() 的一个包装调用,DoMethodA() 接受 NULL 对象指针,但 SetAttrsA() 和 DoMethodA() 中都没有记录这种行为。因此,不要依赖它,而是使用宏来代替,这样可以避免你输入 if 语句。

恢复按钮框架 - 最近使用 D&D,但似乎它与 MUI 自身的 D&D 绘制发生冲突。你可以看看 Ambient D&D 以寻找思路。它使用它自己的拖放标记。

MUI_DISPATCH(NewList_Dispatcher)
{
    switch (msg->MethodID)
    {
        case OM_NEW              : return(NewList_New  (cl,obj,(APTR)msg));
        case OM_SET              : return(NewList_Set  (cl,obj,(APTR)msg));
        case OM_GET              : return(NewList_Get  (cl,obj,(APTR)msg));
        
        case MUIM_DragQuery : return(NewList_DragQuery(cl,obj,(APTR)msg));
        case MUIM_DragDrop   : return(MyList_DragDrop (cl,obj,(APTR)msg));
        case MUIM_ExternDrop :return(MyList_ExternDrop(obj,(APTR)msg));
    }
    return(DoSuperMethodA(cl,obj,msg));
}

为每个复选框添加了一个内部通知方法,并将该方法添加到调度器中。

DISPATCHERPROTO(MCC_BIA_dispatcher)
{
struct mydata *mydata = INST_DATA(cl,obj);

switch (msg->MethodID)
{
case OM_NEW: return( MCC_BIA_New (cl, obj, (APTR) msg));
case OM_SET: return( MCC_BIA_Set (cl, obj, (APTR) msg));
case OM_GET: return( MCC_BIA_Get (cl, obj, (APTR) msg));
case OM_DISPOSE: return( MCC_BIA_Dispose (cl, obj, (APTR) msg));
case MUIM_AskMinMax: return( MCC_BIA_AskMinMax (cl, obj, (APTR) msg));
case MUIM_BIA_Changed: return( MCC_BIA_Changed (cl, obj, (APTR) msg));
default: return( DoSuperMethodA (cl, obj, msg)); 
}
}

每次点击一个复选框时,你都会收到一个 MUIM_BIA_changed,并且会调用该函数。在函数中,读取复选框并重建位数组,可以使用 MUIA_BIA_Array 标签来读取和设置它。

现在需要一个针对 MUIA_BIA_Array 的通知。我需要使用 set(MUIA_BIA_Array) 调用该类本身来触发通知吗?还是有更简单的方法?从内部调用该类会导致复选框发生变化,这会导致另一个 MUIM_BIA_changed,从而形成一个无限循环。

问题是设置会导致更新类内部的小部件。这些会导致通知,而通知又会导致另一个设置。

//The best way to handle it is to filter out tag list..
struct TagItem *tagitem;
tagitem = FindTagItem( MUIA_xxx_name, taglist );
if( tagitem != NULL )
{
tagitem->ti_Tag = TAG_IGNORE;
}

do-notify set 可能仍然会在某些情况下导致无限循环,这些情况取决于超类属性的实现,因此在一个类版本中工作正常,而在另一个类版本中会导致系统崩溃...

MUIA_ApplicationObject 
MUIA_AppMessage	
MUIA_HelpLine 
MUIA_HelpNode 
MUIA_NoNotify 
MUIA_ObjectID 
MUIA_Parent 
MUIA_Revision 
MUIA_UserData 
MUIA_Version

MUIM_CallHook 
MUIM_Export 
MUIM_FindUData 
MUIM_GetConfigItem 
MUIM_GetUData 
MUIM_Import 
MUIM_KillNotify 
MUIM_KillNotifyObj 
MUIM_MultiSet 
MUIM_NoNotifySet 
MUIM_Notify 
MUIM_Set 
MUIM_SetAsString 
MUIM_SetUData 
MUIM_SetUDataOnce	
MUIM_WriteLong 
MUIM_WriteString 
// Create your GUI 
 app = ApplicationObject,
 SubWindow, wnd = WindowObject,
 MUIA_Window_Title, (IPTR) "Title",
 MUIA_Window_CloseGadget, FALSE,

 WindowContents, (IPTR) VGroup,
  MUIA_Group_SameWidth, TRUE,

  Child, (IPTR) HGroup,

   Child, (IPTR) VGroup,

    Child, TextObject,
    MUIA_Text_Contents, "33cText1",
    End,

    [...]

   End,

   Child, VGroup,

    Child, TextObject,
    MUIA_Text_Contents, "33cText2",
    End,

    [...]

   End,

   Child, VGroup,

    Child, TextObject,
    MUIA_Text_Contents, "33cText3",
    End,

    [...]

   End,

   Child, VGroup,

    Child, TextObject,
    MUIA_Text_Contents, "33cText4",
    End,

    [...]

   End,

   Child, VGroup,

    Child, TextObject,
    MUIA_Text_Contents, "33cText5",
    End,

    [...]

   End,

   Child, VGroup,

    Child, TextObject,
    MUIA_Text_Contents, "33cText6",
    End,

    [...]

   End,
  End,

  Child, HGroup,

   Child, Scan_button = SimpleButton("Button"),
   Child, Quit_button = SimpleButton("Quit"),
  End,
 End,
 End,
 End;
 Object *exampleWinObj, *exampleVirtGObj, *exampleContainerObj;

Object *exampleChildObj;

exampleWinObj = (Object *)WindowObject,
                    MUIA_Window_CloseGadget, FALSE,
                    MUIA_Window_Title, (IPTR)"Example Window",
                    WindowContents, (IPTR) (exampleVirtGObj= (Object *)GroupObject,
                        MUIA_Group_Virtual, TRUE,
                        Child, (exampleContainerObj = (Object *)VGroup,
                        End),
                    End),
                End;

if (exampleWinObj)
{
    int i;
    for (i = 0; i < 10; i++)
    {
        exampleChildObj = HVSpace;

        if (DoMethod(exampleContainerObj, MUIM_Group_InitChange))
        {
            DoMethod(exampleContainerObj, OM_ADDMEMBER, exampleChildObj);
            DoMethod(exampleContainerObj, MUIM_Group_ExitChange);
        }
    }
}

更改您要添加的任何对象(组等)的 HVSpace。

已过时的钩子。

MUI 不允许组件的自定义位置,只提供自动位置(组概念),但通过设置布局钩子,并为每个对象添加 Left、Top、Width 和 Height,可以禁用此行为。

您的通知最好调用负责您想要执行的操作的类的某个方法。倾向于在窗口或应用程序子类中收集更通用的内容。如果确实没有合适的位置,则可以调用钩子。

您必须添加自己的布局钩子,它报告大小。然后只需在您的 virtgroup 对象上调用 MUIM_Group_Init/ExitChange,因为这将导致重新布局 == 调用您的布局钩子,它可以报告内容的新大小。如果您的家族树需要任何布局(在渲染之前),那么布局钩子也是理想的选择。请查看 Aminet 上的 2b_VRastPort 源代码。

/* gcc syntax */
ULONG __attribute__((regparm(3))) Genealo_Layout(struct Hook *hook, struct
MUI_LayoutMsg *lmsg, Object *obj )
{
ULONG result = 0;
int longueur=500, haut=500;

switch(lmsg->lm_Type)
{
case MUILM_MINMAX:
{
printf("MinMax\n");
lmsg->lm_MinMax.MinWidth = 500;
lmsg->lm_MinMax.MinHeight = 500;
lmsg->lm_MinMax.MaxWidth = 500;
lmsg->lm_MinMax.MaxHeight = 500;
lmsg->lm_MinMax.DefWidth = 500;
lmsg->lm_MinMax.DefHeight = 500;
}
break;

case MUILM_LAYOUT:
{
printf("Layout...\n");

lmsg->lm_Layout.Width = longueur;
lmsg->lm_Layout.Height = haut;
result = TRUE;
}
break;
}
return result;
}
ULONG __attribute__((regparm(3))) Genealo_Dispatcher(struct IClass *cl ,
void *msg,Object *obj )
{
Msg msg2 = ( Msg ) msg;
struct Genealo_Data *data;
ULONG result;

switch (msg2->MethodID)
{
case OM_NEW:
{
result = DoSuperMethodA(cl,obj,msg);
if(obj = (Object *)(result))
{
data = (struct Genealo_Data *)INST_DATA(cl,obj);

data->LayoutHook.h_Entry = (ULONG(*) ())Genealo_Layout;
data->LayoutHook.h_Data = data;
SetAttrs(obj,MUIA_Group_LayoutHook, &data->LayoutHook,TAG_DONE);
}
printf("%p\n",result);
return( result );
}
break;
/* ..... */

如何在 MUI 中进行多线程操作,让同一个线程同时运行多次?您的应用程序树只能被一个任务访问,因为没有 MUI 对象是可重入的或线程安全的(类是,对象不是)。使用

DoMethod(app,MUIM_CallHook,&hook)

在同时运行不同线程时效果很好,但在第二次调用同一个钩子时,第一个钩子会暂停。这是因为两个线程都在同一个 OS 任务上运行。如果您想让它们同时运行,您必须为每个线程创建一个单独的任务,例如通过 dos.library 中的 CreateProc()。该方法与 CallHookA(&hook, app, NULL) 相同,而 CallHookA(&hook, app, NULL) 又与直接调用钩子函数相同,参数为 'app' 和 '&hook'。我不确定您为什么认为这等于“多线程”。如果第二个事件随后终止,第一个事件将继续,但所有局部变量似乎都已被第二个事件更改。因为您的代码不可重入。

IClass 中也存在一个用户字段,您可以像在 Dispatcher 中一样通过 MUI_CreateCustomClass() 访问它。

mcc = MUI_CreateCust..()
mcc->mcc_Class->cl_UserData = data;

在 Dispatcher 中

data = cl->cl_UserData;

使用 MUIA_UserData 和 MUIM_FindUData 在树中定位对象

使用 MUIA_UserData 存储指向私有结构的指针,在该结构中,IT 存储对象/相关代码可能需要的信息...例如指向路径/文件名等的指针,任何您喜欢的。

对象的 MUIA_UserData 包含给定的 udata,并在这种情况下返回对象指针。

区域(拖动、右键点击等)

[编辑 | 编辑源代码]

让程序知道用户是否点击了地图上的任何位置,答案是肯定的:组类是区域类的子类,因此您可以使用区域类的任何属性,例如 MUIA_Pressed。

让程序知道用户是否以及在什么位置点击了地图,答案是否定的。这正是自定义类存在的意义。如果任何绘制操作都将由用户进行操作(例如,使用鼠标进行绘制的区域),您将编写一个 Area 类的子类。位图仅用于显示光栅图像。如果您想拥有一个(可调整大小的)区域用于应用程序特定的绘制,子类化 Area 仍然是正确的做法。

如果您想创建它们的平铺位图,然后将其显示在应用程序内部。对于此应用程序,使用包含位图对象的子项的列组,甚至使用具有自定义 LayoutHook 的组来根据区域的大小调整列数,肯定会更简单。

// want the image to be the same size as the picture or if the object has to be bigger then the picture,
// it should be centered (horiz and vertically). 
TextAttr ta = { "topaz", 8, 0, 0 };
TextFont *Topaz8Font = OpenFont(&ta);

Object *guiobject = ImageObject,
MUIA_Image_Spec, "5:<path>",
MUIA_Image_FreeHoriz, FALSE,
MUIA_Image_FreeVert, FALSE,
MUIA_Image_FontMatch, TRUE,
MUIA_Font, Topaz8Font,
End;

Image 类是 Area 类的子类,Area 类可以处理输入,因此应该可以创建一个行为像普通按钮的 Image 对象。只需尝试创建一个 Image 对象,将 MUIA_Image_Spec 属性初始化为“5:picture_filename”(通过数据类型加载图像),并尝试将 Area 类属性 MUIA_InputMode 初始化为 MUIV_InputMode_RelVerify。

然后为该对象设置一个通知,这样您就可以收到它的消息,打开窗口...

查看 mui.h 中图像和按钮的“默认宏”可能会有所帮助,以便正确初始化其他属性(框架类型等)。

  1. 在对象的父组上调用 MUIM_Group_InitChange。
  2. 从组中 OM_REMMEMBER 它。
  3. 更改大小,即您应该修改 MUIM_AskMinMax 中使用的数据来填充结构。
  4. OM_ADDMEMBER 将其放回。
  5. 在组上调用 MUIM_Group_ExitChange。
MUIM_DRAW
[编辑 | 编辑源代码]

如果您想自己编写您的类将要显示的内容(例如,使用 mui 类 1 demoprogram 的线框绘制),您将在覆盖 MUIM_Draw 方法时实现这一点。(请查看自定义类 class1(正常)、class2(正常)、class3(已过时)的三个示例。

是否可以在 MUIM_Draw 之外绘制对象?与直接绘制(如 gadtools 中的绘制)相比,MUIM_Draw 会增加一些开销,但开销非常小,您也无法注意到任何速度下降...

有没有一种安全的方法可以在绘制事件之外绘制到窗口/MUI 对象中?您只能在 MUIM_Draw 内绘制,因为

  • 您的对象可能属于虚拟组,并且需要裁剪(MUI 会自动为 MUIM_Draw 安装裁剪)。
  • 您的应用程序随时可能隐藏(处于图标化状态),因此 _rp(obj) 并不总是有效的。
  • 您的对象可能由于某些原因而被隐藏(页面和寄存器组)。

如果您只是想绘制对象的新品而不进行完全重绘?然后您可以执行以下操作

data->DrawCommand = MY_OWN_DRAW_COMMAND;
MUI_Redraw(obj, MADF_DRAWUPDATE);

然后在您的 MUIM_Draw 方法中

MyDraw()
{
DoSuperMethod();

if (msg->flags & MADF_DRAWUPDATE)
{
switch (data->DrawCommand)
{
/* UPDATE PARTS YOU WANT TO */
}
}
else
{
/* FULL REDRAW */
}
}

在 MUIM_Draw 中只需调用 BltBitMapRastPort() 即可在屏幕上显示内容

BltBitMapRastPort(data->RastPort.BitMap, 0, 0, rp, mleft, mtop , mwidth, mheight, 0xc0);

创建一个位图,将其嵌入到一个光栅端口中,并将此光栅端口设置为您的 MUI 渲染信息 - 然后只需调用 MUIM_DrawBackground,背景就会绘制到您的屏幕外位图中。请记住将光栅端口设置回

在您的对象区域内,您可以完全自由地渲染您想要的内容。关于光栅端口:如果您使用任何 graphics.library 函数,您 *应该* 将自己的光栅端口附加到对象:Mui 预期在执行 MUIM_Draw 后在相同状态下找到对象的自己的光栅端口。

如果未调用 MUIM_Draw(带有框架的空白区域),请检查您是否没有首先在 MUIM_Draw 方法中调用 DoSuperMethodA(),并且 MUIM_Draw 方法只检查 msg->flags == MADF_DRAWOBJECT。

switch( msg->MethodID )
{
[...]
case MUIM_Draw: return( draw( class, object, msg ) );
[...]
}

解决了问题,在绘制方法中替换了它们

if(!DoSuperMethodA(cl,obj,(APTR)msg)) 
    DoSuperMethodA(cl,obj,(APTR)msg);

通常情况下,您的对象应该有一个内部缓冲区,在该缓冲区中存储上次 MUIM_Draw 后的对象状态。这使您能够只绘制需要更新的那些地图部分。

将参数填充到您的实例数据中,并使用 MADF_DRAWUPDATE 调用 MUI_Redraw()。这就是它的用途。基本上,所有渲染都在 MUIM_Draw 内部完成。如果另一个方法想要渲染,它会设置参数并调用 MUI_Redraw()。然后 MUI_Redraw() 会为您调用 MUIM_Draw。

但是,您必须意识到 MUIM_Draw 可能 *不会* 被调用,例如,当您的对象当前处于隐藏状态时。因此,MUIM_Draw 应该只绘制;您的其他方法应该执行所有其他操作(如果您绘制一个椭圆,您必须将该信息存储在某处,以防刷新出现、应用程序图标化等。因此,您的 MUIM_xxx_DrawEllipse 将将所有这些信息存储在某处(将椭圆添加到列表中或将其绘制到屏幕外位图中),然后它将调用 MUI_Redraw(TheObject,MADF_DRAWUPDATE) 来更新显示)。

带有 mui 按钮的 3ds 视图器怎么样?Titler 显示 opengl 和 mui 在同一个窗口中,那么什么类/方法可以用来显示/将 opengl 输出重定向到 mui 窗口?您需要一个区域子类来在 MUI 窗口中显示您的 GL 内容。您只需要一个屏幕外位图,该位图在您的 MUIM_Draw 方法中被 blit 到窗口中。

InitRastPort(&data->RastPort) 在代码的其他部分完成!一旦 opengl 上下文初始化完毕,您就可以使用 GL 调用将内容渲染到屏幕外位图中。

请查看 aminet/wazp3d 中的 soft3d_opengl.c。里面有代码用于为 aros 启动 mesa(查找 ifdef aros...)。但是 aros mesa 无法在位图中渲染:您需要使用 mui 窗口 + glscissor。

AreaGL 可能会有所帮助。

MUIA_Image_FontMatch
MUIA_Image_FontMatchHeight
MUIA_Image_FontMatchWidth
MUIA_Image_FreeHoriz
MUIA_Image_FreeVert
MUIA_Image_OldImage
MUIA_Image_Spec
MUIA_Image_State
MUI_Redraw
[编辑 | 编辑源代码]

使用 MUI_Redraw(),对象会告诉自己刷新,例如,当某些内部属性发生更改时。在自定义类调度程序中,调用 MUI_Redraw() 是唯一合法的,“在应用程序主部分内使用此函数是无效的!”。为了解决我在 UAE 端口的 AROS GUI 中遇到的相同问题,我将 MUI_Redraw 包裹在一个自定义方法中。

MUIM_UAEDisplay_Update, struct MUIP_UAEDisplay_Update *,
({

if (message->top >= data->height || message->bottom <= 0)
return TRUE;

if (message->top <= 0)
message->top = 0;

data->update_top = message->top;
data->update_bottom = message->bottom;

MUI_Redraw(self, MADF_DRAWUPDATE);

return TRUE;
})

case OM_SET:
{
struct TagItem *tagitem, *tagstate = msg->ops_AttrList;
while( tagitem = NextTagItem( &tagstate ) )
{
case MUIA_[classname]_Update:
{
MUI_Redraw( obj, MADF_DRAWUPDATE);
break;
}
}
return( DoSuperMethodA( cl, obj, msg ) );
}

但是,更好的方法可能是将属性设置为传递向量数组。当传递它时,会调用重绘。或者使用自定义方法。

case MUIM_[classname]_Update:
{
MUI_Redraw( obj, MADF_DRAWUPDATE);
return( 0 );
}

您不能完全拦截 OM_SET。程序对 Area.mui 或 Group.mui 等某些 MUI 类进行子类化,它们具有自己的属性,这些属性可能在程序运行期间被设置。拦截它们或重绘窗口可能会导致非法操作。

群组类设计为包含其他群组和工具,而不是自身成为一个工具。 这是由于它是区域类的子类(使其成为通知类的子类,复制部分方法将毫无意义)而产生的副作用。 嗯... 如果你想创建一个图像按钮(带有文本和图形的按钮),除了群组类之外,还可以通过创建 MUIC_Area 的子类来完成,该子类在 MUIM_Setup 中使用 datatypes.library 加载必要的图片,在 MUIM_Draw 中绘制它,并在 MUIM_Cleanup 中释放它。 顺便说一下,群组类不是区域类的子类是一个错误。

只有群组对象可以有子对象。 要获取子对象,可以使用 MUIA_Group_ChildList。 通过列表进行遍历使用 NextObject() 完成。 例如

	Object *obj1;
	struct List *children	= (struct List *)XGET(_maingrp, MUIA_Group_ChildList);
	APTR pObj               = GetHead(children);

	// Parse the children
	while(NULL != (obj1 = NextObject((Object **)&pObj)))
	{
		printf("ID is: %ld\n", XGET(obj1,MUIA_ObjectID));
	}

要获取父对象,可以使用 MUIA_Parent。

如果你不知道子对象的数量,或者子对象的数量是可变的,则需要为方法结构分配一些内存(sizeof(struct MUIP_Group_Sort) + sizeof(Object *) * num_children),然后使用 DoMethodA(obj, alloc'd_method) 调用它。 然后再次释放方法结构。

num_children = 在子对象列表上成功调用 NextObject() 的次数。

存在 MUIM_Group_Sort 方法,它允许你告诉群组对象子对象的精确顺序。 NListview.mcc 使用此方法以及 group_initchange/group_exitchange 内容来动态显示/隐藏滚动条。

你对群组设置的几乎所有属性都会转发到其子对象。 你可以将 MUIA_Group_Forward 设置为 FALSE 以防止这种情况(在设置相关标签时)。

一个 MUIM_Group_Insert 方法,用于将子对象插入到群组的指定位置,就像 MUIM_Family_Insert 一样。 目前将子对象列表从群组移动到我的私有家族中,使用 MUIM_Family_Insert 将新子对象插入到我的家族中,然后将所有子对象从家族再次移动到群组中。 在群组上就像 MUIM_Family_Sort 在家族上一样。

#define MUIM_Group_Sort 0x80427417 /* V4 */
DoMethod(parent, MUIM_Group_InitChange);
    DoMethod(parent, REMMEMBER, obj);
    set(obj, MUIA_FixWidth, 100);  // just some changing beyond the object borders
    DoMethod(parent, ADDMEMBER, obj);
DoMethod(parent, MUIM_Group_ExitChange);

在设置/清理期间的 InitChange/ExitChange 不是一个好主意。 你应该在 MUIM_Setup 中添加你的子对象 *在* DoSuperMethod() 之前,并在 MUIM_Cleanup 中删除你的子对象 *在* DoSuperMethod() 之后。

不应该禁用群组来禁用其子对象。 最好禁用每个子对象本身,因为这样看起来会更好。 你可以使用一个 DoMethod 来完成此操作,例如 MUIM_MultiSet 或 MUIM_SetUData

群组旨在用于具有可视表示的对象。 对于文本编辑器,如果你将 Buffer 和 Display 对象分组,这会有点棘手,因为 Buffer 并不是真正的工具。 编辑器应该是 Display 的子类,而 Buffer 应该通过对象数据结构中的指针附加。 它更好地显示了 Buffer 和 Display 之间的联系,它们不仅仅是群组中的工具。

基本上,你需要在删除或添加对象之前调用 MUIM_InitChange,然后调用 MUIM_ExitChange

DoMethod(yourgroup,MUIM_InitChange)
DoMethod(OM_ADDMEMBER,newobject)
DoMethod(yourgroup,MUIM_ExitChange)

通过对 _parent(obj) 执行 MUIM_Group_InitChange 和 MUIM_Group_Exitchange 来触发重新布局

每个对象都应该负责将新设置传递给其子对象。 例如,当你有一个包含数字和字符串工具的群组子类时,它将具有一些属性来保存工具各自值的结构,而群组对象必须知道哪个值属于哪个子对象,并在它本身接收到 OM_SET 时相应地设置它们。 然后,理想情况下,你会执行 set(mywindow,PREFS_ATTRIBUTE,&some_structure),而对象树会自行处理剩下的工作。 然后,除了在某个结构中记住需要更新的每个对象并“手动”设置它之外,别无他法。

virtgroup.mui 是 MUI 的内部部分(它们“位于”muimaster.library 中)。

虚拟群组就像一个容器,如果内容超出其边界,它可以滚动。 虚拟群组在 ScrollGroup 中很有意义。

你不应该使用 MUIA_Pressed 来通知切换工具(只用于 RelVerify 工具,例如按钮)。 使用 MUIA_Selected。

window
---> group (<--- set MaxWidth/MaxHeight here, works)
------> scrollgroup
---------> virtgroup
------------> text
------> rectangle (<--- or here, works, too)

如何获得一个仅在水平方向上虚拟的 virtgroup(不使用 scrollgroup(使用 MUIA_Scrollgroup_FreeVert,FALSE))或者有没有办法始终隐藏滚动条?

你需要一个 自定义类,它使用固定高度或宽度,从而锁定 virtgroup 在垂直或水平方向上。

动态地将对象添加到群组。 首先,你必须 **初始化** 你想要做的更改,然后 **执行** 它们,然后声明你已经 **完成** 了。 添加或删除从另一个群组中的群组的代码示例

        Object *_maingrp = .... // the container
        Object *_subgrp = .... // the content

	// add the subgroup
	if(DoMethod(_maingrp, MUIM_Group_InitChange))
	{
           DoMethod(_maingrp, OM_ADDMEMBER, _subgrp);
           DoMethod(_maingrp, MUIM_Group_ExitChange);
	}

	// remove the subgroup
	if(DoMethod(_maingrp, MUIM_Group_InitChange))
	{
           DoMethod(_maingrp, OM_REMMEMBER, _subgrp);
           DoMethod(_maingrp, MUIM_Group_ExitChange);
	}
LONG sigs;
DoMethod(app,MUIM_Application_NewInput,&sigs);

这似乎是 MUI 程序员的普遍陷阱,但 'sigs' 必须初始化为零! 更糟糕的是:sigs 是 Wait() 的结果,即进程接收到的信号。 因此,如果你给出一个随机值,MUI 会认为收到了随机信号,并根据这些信号采取行动。 通常情况下,这种效果并不明显,因为消息端口信号只会导致“while(GetMsg(port))”,它会立即终止,但在理论上,可能会出现严重的问题

想要重现 Workbench 处理图标的方式。 想要能够将图像从一个点移动到另一个点。 从 Group(虚拟或其他)派生一个类,它有自己的自定义布局钩子,并使该组的对象可拖动; 当你收到一个放置事件时,重新布局该组(使用 MUIM_Group_InitChange = 后跟 ExitChange 强制执行此操作)

TableGroup

MUIM_Group_ExitChange
MUIM_Group_InitChange
MUIM_Group_Sort

MUIA_Group_ActivePage
MUIA_Group_Child
MUIA_Group_ChildList
MUIA_Group_Columns
MUIA_Group_Horiz
MUIA_Group_HorizSpacing
MUIA_Group_LayoutHook
MUIA_Group_PageMode
MUIA_Group_Rows
MUIA_Group_SameHeight
MUIA_Group_SameSize
MUIA_Group_SameWidth
MUIA_Group_Spacing
MUIA_Group_VertSpacing
RMB 和 LMB
[编辑 | 编辑源代码]

RMB 菜单到工具。 上下文菜单是 Area 类的功能,可以使用 MUIA_ContextMenu 设置,或者通过重载 MUIM_ContextMenuBuild 动态创建。 是否可以在 MUI 中使用 rmb 作为 lmb? 是的,你应该为你的对象重载 MUIM_ContextMenuBuild。 创建一个假的 Menu 对象(只有一个菜单,没有项目),将其提供给 MUIA_ContextMenu 属性,并在 MUIM_ContextMenuBuild 中完成你的工作,从那里返回 NULL(这意味着不会绘制上下文菜单)。 嗯,这并不容易,因为没有简单的方法可以获取有关 RMB _释放_ 的信息。 你必须子类化 Text 类并编写自己的 MUIM_HandleInput,这在文档中被提到了,但已经过时。 但不幸的是,MUI 事件处理程序对 RMB 没有反应(MUI 中的错误?)。 可以查看 MUIMine 源代码(在 Aminet 上)。 它做了一些类似的事情,并提到了 RMB 的问题。 它还使用 MUIM_HandleInput。

ULONG MyList_DragQuery(struct IClass *cl,Object *obj,struct MUIP_DragDrop *msg)
{
    if (msg->obj==obj)
    {   //return(MUIV_DragQuery_Accept);
        return(DoSuperMethodA(cl,obj,(Msg)msg));
    }
    else
    {
        if (msg->obj==(Object *)muiUserData(obj))
            return(MUIV_DragQuery_Accept);

        else
            return(MUIV_DragQuery_Refuse);
    }

}

只要没有冲突的输入,MUI 就会立即启动拖动操作。 如果 LMB 需要用于其他用途(例如在按钮上),MUI 会根据首选项中指定的开始拖动。 将 MUI_Draggable 设置为 TRUE,用于 MUI_Area 子类的对象

get(obj,MUIA_List_DropMark,&dropmark);
DoMethod(obj,MUIM_List_InsertSingle,entry,dropmark);

请注意,你必须从目标对象中获取放置标记,*而不是* 从源对象中获取。

一种模式允许你将数据输入到字符串工具中。 另一种模式允许拖动。 在拖动模式下,你将 StringObject 变成 TextObject。 这样一来,你就可以毫无问题地四处拖动对象。 你也可以尝试创建一个自定义字符串类。

如何让 MUI 报告相对于接受放置的对象的放置位置? 还有没有办法让 mui 报告基于抓取对象的顶部、左边缘,而不是报告你从哪里抓取对象的? 如果位置是基于屏幕的,只需从中减去 _mleft(obj) 和 _window(obj)->LeftEdge、_mtop(obj 和 _window(obj)->TopEdge。

有没有办法对 Workbench 图标拖动到用 MUI 创建的应用程序窗口中做出反应。 桌面管理器只在用户停止拖动时向应用程序发送消息,因此这是不可能的。

MUI 有自己的方式来处理 D&D,它使用 MUIM_DragBegin/DragFinish 来处理其 MUI 对象.... MUIM_DragBegin/Finish 用于内部 MUI D&D。 AppWindow 消息是外部生成的,MUI 无法控制它。

这通常是你通常不会自己调用的方法(就像 area.mui 的拖放方法一样)

MUIM_AskMinMax
MUIM_Cleanup
MUIM_ContextMenuBuild
MUIM_ContextMenuChoice
MUIM_CreateBubble
MUIM_CreateShortHelp
MUIM_DeleteBubble
MUIM_DeleteShortHelp
MUIM_DragBegin
MUIM_DragDrop
MUIM_DragFinish
MUIM_DragQuery
MUIM_DragReport
MUIM_Draw
MUIM_DrawBackground
MUIM_HandleEvent
MUIM_HandleInput
MUIM_Hide
MUIM_Setup
MUIM_Show

MUIA_Background
MUIA_BottomEdge
MUIA_ContextMenu
MUIA_ContextMenuTrigger
MUIA_ControlChar
MUIA_CycleChain
MUIA_Disabled
MUIA_Draggable
MUIA_Dropable
MUIA_ExportID
MUIA_FillArea
MUIA_FixHeight
MUIA_FixHeightTxt
MUIA_FixWidth
MUIA_FixWidthTxt
MUIA_Font
MUIA_Frame
MUIA_FramePhantomHoriz
MUIA_FrameTitle
MUIA_Height
MUIA_HorizDisappear
MUIA_HorizWeight
MUIA_InnerBottom
MUIA_InnerLeft
MUIA_InnerRight
MUIA_InnerTop
MUIA_InputMode
MUIA_LeftEdge
MUIA_MaxHeight
MUIA_MaxWidth
MUIA_Pressed
MUIA_RightEdge
MUIA_Selected
MUIA_ShortHelp
MUIA_ShowMe
MUIA_ShowSelState
MUIA_Timer
MUIA_TopEdge
MUIA_VertDisappear
MUIA_VertWeight
MUIA_Weight
MUIA_Width
MUIA_Window
MUIA_WindowObject

register (TABS)

[编辑 | 编辑源代码]

一个 register(Tab)的子对象(一个 tab)如何知道它当前是否可见,而不必知道它位于哪个 tab 中? 拥有一个 .mcc,它是一个 group 的子类,并创建一行 cycletitle-objects(类似于 cycle 工具,但有一个固定标题字符串在 cyclegadget 中),每个按钮代表一个窗口。 该组在打开新窗口或关闭一个窗口时会收到通知(由 notifyintuition.library 通知)。 或者创建一个 group 的子类,它有一个新属性,例如 MUIA_XGroup_PageIndex。 然后,你可以将此属性与“主组”对象的活动页面进行比较。 你应该知道“主组”对象,因为它从读取“选项卡页面”的 MUIA_Parent 获取此信息。

if tabpage.pageindex = tabpage.parent.activepage then (simple pseudo code)

或者创建一个 register 的子类,除了 MUIA_Group_ActivePage 之外,它还有 MUIA_Group_ActivePageObj,该属性在 MUA_Group_ActivePage 发生更改时设置。 然后,你可以将此属性与“选项卡页面”进行比较。

if tabpage = tabpage.parent.activepageobj then (simple pseudo code)

或者创建一个 register 的新方法,该方法返回当前的 obj(类似于你的上述想法),但作为一个方法,它将适用于你所有的 register 组。

MUIA_Register_Frame
MUIA_Register_Titles
列表的优秀示例
  • 列表类是一个可以保存和操作(在一定程度上)数据链表的类。
  • 列表视图类是一个 group 子类,它处理列表的布局和互连以及所需的滑块。

Listtree 使用图像作为分支,但据我所知,它不允许你更改图像。

在启动时,列表为空,并使用 MUIM_List_InsertSingle 添加条目。

将 MUIA_List_SourceArray 分配给一个 strarray,然后将 MUIA_List_Active 的结果用作该数组的索引。

MUIM_List_Remove

使列表视图具有文本内部的宽度,不多不少。

MUIA_List_Format - MAXWIDTH/MINWIDTH
MUIA_List_AdjustWidth, TRUE

在 ListView 中插入字符串

DoMethod(projectfiles,MUIM_List_InsertSingle,(long unsigned int)TXT.sfilename.c_str(),(IPTR)MUIV_List_Insert_Bottom);

COPYING 你需要定义 Construct 和 Destruct 钩子,因为 List 对象不会复制你的字符串(只获取一个指针),直到你另外发出指令。 如果你有一个简单的单列列表,并且你对在其中存储字符串感到满意,MUI 提供了用于此目的的内置构造钩子。 请参阅自动文档以了解构造和析构(必须设置两者!)。

MUIA_List_ConstructHook, MUIV_List_ConstructHook_String
MUIA_List_DestructHook, MUIV_List_DestructHook_String

MUIV_List_Remove_Selected

你可以在列表类完成其设置方法后立即调用 MUIM_List_CreateImage。 你必须在列表完成其清理方法之前调用 MUIM_List_DeleteImage。

MUIM_Insert_xyz 将一个对象插入到列表中,这意味着列表类可以处理任何对象,因此你不能只向其添加字符串。 只有指针被存储,而不是它的内容。 请注意,列表不负责显示其内容,这是由 Listview 完成的,默认情况下,它的显示钩子期望列表中的 Text 指针。

如何在列表中添加一个字符串旁边的较小图像? game/think/MUIMastermind.lha 可能有一个简单的方法,不需要 CreateImage() 等等。

读取 MUIA_List_Active 会提供给我条目号,但如果顺序发生变化,它就不再有任何意义? GetEntry 返回你的条目的指针,你可以访问你想要的任何列。 无论如何,它都是你的私有指针。

如果你想为应用程序添加页面背景,只需在你的 group 对象上使用 MUIA_Background、MUII_PageBack。

**过时的钩子。** 如果使用了钩子,则使用多列 List 对象来显示结果,但想要为列添加标题

HOOKPROTO(ResultList_Display, ULONG, char **array, struct ReqData *reqdata)
{
if (reqdata) {

int n;
for (n=0; n<reqdata->nb ; n++) {
*array++ = reqdata->columns[n];
}
} else {
reqdata = (struct ReqData *)hook->h_Data; // list titles

int n;

for (n=0; n<reqdata->nb ; n++) {
*array++ = reqdata->columns[n];
}
}

return 0;
}
MakeStaticHook(hook_ResultList_Display, ResultList_Display);

Somewhere in your code you set h_Data:

hook_ResultList_Display.h_Data = (APTR)reqdata_titles;

你可以创建一个钩子对象,其 h_entry 部分是你的函数,并使用 MUIM_CallHook,或者子类化对象 id_main_add,以便它处理特定方法,并且在你的方法被接收的情况下,调用你添加的某些函数(这是推荐的方法).. callhook 内容将类似于

struct Hook h = { addsome, NULL, NULL };
DoMethod(id_main_add, MUIM_Notify, MUIA_Pressed, FALSE, id_main_add,2, MUIM_CallHook, &h );

对于 AROS,你需要更改

#define MUI_LIST_DISP(x,y) ULONG SAVEDS ASM x (REG(a2,char **array), REG(a1, y ))
to
#define MUI_LIST_DISP(x,y) ULONG SAVEDS ASM x (REG(a0,struct Hook *h), REG(a2,char **array), REG(a1, y ))

以便将指向 Hook 的指针作为第一个参数。对于其他 [hook 宏 http://aros.sourceforge.net/documentation/developers/headerfiles/aros/asmcall.h] 也是如此。

我们在 [文档 http://aros.sourceforge.net/documentation/developers/app-dev/portable.php#hooks] 中提供了一些关于钩子的提示。

MUIM_List_Clear
MUIM_List_CreateImage
MUIM_List_DeleteImage
MUIM_List_Exchange
MUIM_List_GetEntry
MUIM_List_Insert
MUIM_List_InsertSingle
MUIM_List_Jump
MUIM_List_Move
MUIM_List_NextSelected
MUIM_List_Redraw
MUIM_List_Remove
MUIM_List_Select
MUIM_List_Sort
MUIM_List_TestPos

MUIA_List_Active
MUIA_List_AdjustHeight
MUIA_List_AdjustWidth
MUIA_List_AutoVisible
MUIA_List_CompareHook
MUIA_List_ConstructHook
MUIA_List_DestructHook
MUIA_List_DisplayHook
MUIA_List_DragSortable
MUIA_List_DropMark
MUIA_List_Entries
MUIA_List_First
MUIA_List_Format
MUIA_List_InsertPosition
MUIA_List_MinLineHeight
MUIA_List_MultiTestHook
MUIA_List_Pool
MUIA_List_PoolPuddleSize
MUIA_List_PoolThreshSize
MUIA_List_Quiet
MUIA_List_ShowDropMarks
MUIA_List_SourceArray
MUIA_List_Title
MUIA_List_Visible

字符串

[编辑 | 编辑源代码]

如何获取 MUI 字符串小部件变为活动时的通知?这样我就能知道用户何时点击了小部件并激活了光标,但在他们开始输入任何内容之前?我尝试将 MUIA_InputMode 设置为 MUIV_InputMode_RelVerify 和 MUIV_InputMode_Immediate,但它们都不适用于 MUIA_Pressed 或 MUIA_Selected 通知。

构建 String.mui 的子类,并在 MUIM_GoActive 和 MUIM_GoInactive 方法中执行您需要执行的操作。

将来自“文本框”(使用 Zune/MUI)的输入转换为浮点数。

get(my-string-object, MUIA_String_Contents, &str);
    stcd_l(str, &num);

对小部件进行子类化并重载 MUIM_GoInactive。确保您考虑了用户可能遇到的所有情况,例如暂时离开小部件以从其他地方复制其余值或类似情况。需要对字符串小部件进行子类化并添加自己的事件处理程序。作为解决方法(恕我直言),当您返回 0 时返回 DoSuperMethodA(cl,obj,(Msg)msg);

您可以通知 MUIA_String_Contents,它将在内容每次更改时触发。您可能还可以使用 MUIA_Window_ActiveObject,它应该在小部件变为非活动时设置为除字符串小部件之外的所有内容。如果您使用的是字符串小部件替换之一,那么还可以重载字符串类(Textinput、Newstring 或 Betterstring)的 MUIM_GoInactive。但请记住,使小部件停用(使用 Tab、鼠标、打开新窗口或类似操作)绝不应有确认效果!

MUIA_String_Accept
MUIA_String_Acknowledge
MUIA_String_AdvanceOnCR
MUIA_String_AttachedList
MUIA_String_BufferPos
MUIA_String_Contents
MUIA_String_DisplayPos
MUIA_String_EditHook
MUIA_String_Format
MUIA_String_Integer
MUIA_String_LonelyEditHook
MUIA_String_MaxLen
MUIA_String_Reject
MUIA_String_Secret

数字(滑块、旋钮、电平表等)

[编辑 | 编辑源代码]

在没有悬停在小部件上时释放按钮被认为是“取消”操作。就像“哎呀!我无意中按了按钮,但现在我不想退出,所以我会将鼠标移开”。滑块也会保留您在鼠标在小部件外部释放时拖动到的值。

如何获取滑块在仅释放时通知?我尝试了 MUIA_Pressed,但它不起作用。如果您也使用 Area.mui/MUIA_InputMode。另外,我注意到 MUIA_Slider_Level 说(已过时)。请改用 MUIA_Numeric_Value。

如果按 Tab 键循环选项。我该如何实现?您只需在所有要成为循环链一部分的对象中将 MUIA_CycleChain(区域类)设置为 TRUE。

循环对象

STRPTR colors[] = { "Red", "Green", "Blue", NULL };
ULONG colorsV;
STRPTR ch;
// then in the program...
get(cy1, MUIA_Cycle_Active, &colorsV);
ch = (char *)colorsV;

Cycle_active 包含所选项目的编号。要获取字符串,您需要执行以下操作

ch = colors[ colorsv ];

由于 MUIA_Cycle_Entries 是 [I..],因此唯一的方法是在每次想要更改条目时创建一个新的循环。为此,您需要对包含循环的组执行 MUIM_Group_InitChange,然后 OM_REMMEMBER 旧的循环,OM_ADDMEMBER 新的循环,并执行 MUIM_Group_ExitChange。您可能需要使用 MUIM_Group_Sort 使循环处于正确的位置,或者将其放入一个单独的组中。

有人能告诉我是否有可能创建一个动态循环小部件?您可以通过删除小部件并使用更改后的 MUIA_Cycle_Entries 创建一个新的小部件来“模拟”它。为此,请使用 MUIM_Group_InitChange/ExitChange。

MUIA_Cycle_Active
MUIA_Cycle_Entries

具有渐变背景的滑块。您可以通过 MUIA_Background 设置渐变(但属性字符串未记录)或者可能重载 MUIM_DrawBackground...

在未按下时看起来像普通按钮的滑块,但在按下时,它们会弹出并变成滑块。它们节省了大量空间。它是一个 NumericbuttonObject - 它在演示程序 Slidorama 中使用。

MUIM_Numeric_Decrease
MUIM_Numeric_Increase
MUIM_Numeric_ScaleToValue
MUIM_Numeric_SetDefault
MUIM_Numeric_Stringify
MUIM_Numeric_ValueToScale

MUIA_Numeric_CheckAllSizes
MUIA_Numeric_Default
MUIA_Numeric_Format
MUIA_Numeric_Max
MUIA_Numeric_Min
MUIA_Numeric_Reverse
MUIA_Numeric_RevLeftRight
MUIA_Numeric_RevUpDown
MUIA_Numeric_Value

Mui 有自己的菜单方法,但旧的 NewMenu 调用仍然可以使用。

最好的方法可能是通过窗口类子类创建和释放所需的上下文菜单。菜单项设置为当前活动窗口?在这种情况下,您可以为每个窗口设置不同的菜单,最好是在窗口子类内部,并使用通知来调用您的窗口类的方法或属性,这样它就可以做出反应。

如何通过按下带有 Shift、Control 和 Alt 键的快捷键组合来通知?我尝试了以下代码

DoMethod(win, MUIM_Notify,MUIA_Window_InputEvent, "-control x",app, 2,MUIM_Application_ReturnID,MEN_RUN);

但我每次按下 X 键都会收到通知(无论 Control 是否按下)。

您需要在您的类中为此使用一个普通的事件处理程序。请勿使用返回的内容?因此我看到唯一的方法是使用原始键钩子。想要在菜单项中使用此类快捷键,它们太多了,因此我无法使用 Amiga 的组合来设置每个快捷键。菜单项“MUI 设置...”要将通知设置为调用 MUIM_Application_OpenConfigWindow 的菜单项

执行此操作的方法是在您的子类之一(MUIC_Window 或窗口的 Root MUIC_Group 始终是安全的选项)中实现一个 MenuTrigger 方法,并让 MUIA_Window_MenuAction 通知调用它。您可以在其中使用所有 ID 的 switch,或者简单地使用 methodID 而不是菜单 ID 并像这样执行操作

ULONG mMenuTrigger(struct IClass *cl, Object *obj, struct mpMenuTrigger *msg)
{
DoMethod(obj, msg->menutriggercommand);
}

一旦所有菜单触发器都很好地完成为方法(例如 MUIM_MyClass_Open、MUIM_MyClass_DoSomething),并且您已经使用这些 ID 构建了一个菜单,您也可以在前面提到的 Group 子类中实现一个事件处理程序,并将原始键简单地映射回方法。这可以使用类似以下内容来很好地完成

struct MenuKey
{
ULONG methodForQualifierShift;
ULONG methodForQualifierControl;
ULONG methodForQualifierAlt;
ULONG methodForQualifierAltShift;
};

然后像这样映射它们

struct MenuKey hotkeys[256] = 
{
{0, MUIM_MyClass_Jump}, // RAWKEY_TILDE
{MUIM_MyClass_First}, // RAWKEY_1
....
};

因此您可以轻松地将每个键组合映射到一个方法。

好吧……只是解决此问题的许多方法之一,但它可以让您在源代码中获得一个不错的面向对象的结构。

添加了对 msg->imsg->Code==MENUDOWN 的检查,它会对按下 RMB 做出反应并停止计时器。我还做了相反的 msg->imsg->Code==MENUUP,它会再次启动计时器。但是 - 一旦菜单打开,鼠标按钮按下就会附加到菜单而不是我的窗口/对象,因此 MENUUP 按钮事件永远不会被看到,因此我的计时器保持停止状态,并且在使用菜单后不会再次启动。您可以使用 MUIA_Window_MenuAction 在选择菜单项时收到通知,

DoMethod (win, MUIM_Notify, MUIA_Window_MenuAction, MUIV_EveryTime, obj, 2, MM_Main_MenuAction, MUIV_TriggerValue); 

不确定在未选择任何项目时属性是否会触发……

检查窗口激活也没有帮助,因为当菜单打开时窗口保持活动状态,因此没有任何变化。您可以添加一个全局输入处理程序来检查 RMB 按下和释放,然后检查鼠标指针是否悬停在您的窗口上……

冗余 MUIA_Application_Menu 和 MUIA_Window_Menu(旧的 New Menus 系统)

冗余 MUIM_Application_GetMenuCheck、MUIM_Application_GetMenuState、MUIM_Application_SetMenuCheck、MUIM_Application_SetMenuState

冗余 MUIM_Window_SetMenuCheck、MUIM_Window_SetMenuState、MUIM_Window_GetMenuCheck、MUIM_Window_GetMenuState

MUIA_Menu_Enabled
MUIA_Menu_Title
[编辑 | 编辑源代码]

Menustrip 类是 MUI 面向对象菜单的基础类。它的子类是 Menu 类对象,每个对象都准确地描述了一个菜单。

Menustrip 对象本身没有提供很多选项,但作为 Family 类的子类,它只是充当多个 Menu 对象的父类。

Menustrip 对象通常被指定为 Application 类或 window 类的子类,并带有属性 MUIA_Application_Menustrip 或 MUIA_Window_Menustrip。

您是否尝试使用 MenustripObject 和 MenuObject 而不是 MenuitemObject,以及 MUIA_Menu_Title 而不是 MUIA_Menitem_Title?老实说,我不确定这些宏在 AROS 中是否都存在。

层次结构是:MenustripObject -> MenuObject -> MenuitemObject

在以前,在所有地方都使用菜单项是可以的,但它与 MUI 不兼容,因此发生了更改。

使用家庭对象(来自 Wanderer/Info)

DoMethod(_win(obj), MUIM_Notify, MUIA_Window_MenuAction, MUIV_EveryTime, obj, 2, MUIM_MySubClass_MenuThingy, MUIV_TriggerValue);

在 muidevs 中的 MUIA_Window_MenuAction 部分详细了解菜单。

另请参阅 AROS contrib-source 的 DiskSpeed 抽屉中的 DiskSpeed.c。

在一个 MenuItem 标签中,在该菜单项的 ID 前面没有“MUIA_UserData”标签标识符,因此在 dispose 时,gcc 以某种方式释放了导致崩溃的内存区域,而 sas/c 以某种方式没有这样做。

entry = MUI_MakeObject(MUIO_Menuitem,advance_name_translation(i),NULL,0,0);
set(entry,MUIA_UserData,i);
DoMethod(entry,MUIM_Notify,MUIA_Menuitem_Trigger, MUIV_EveryTime, entry,6, MUIM_CallHook, &civstandard_hook, diplomacy_tech, pdialog, plr0->player_no,entry);
DoMethod(menu_title,MUIM_Family_AddTail, entry);
MUIA_Menustrip_Enabled

请求者

[编辑 | 编辑源代码]
MUI_Request(app, mainwnd, 0L, "Sorry...", "Close", "...but this feature is not yet implemented", NULL);

要么在这些庞大的 MUI 结构之外创建您的新对象,并在其中使用一个指针,要么删除“End”宏并用“TAG_DONE)”替换它。在 MOS 和 AmigaOS 上,NewObject 可变参数函数保存在静态库中。它在堆栈上获取大多数参数 - 因此 NewObject 的实现调用 NewObjectA 函数。一切正常,典型的 MUI 宏可以轻松使用。

然而,当你为 AROS 编译时情况并非如此。在这里,NewObject 是一个可变参数宏,而不是一个函数。由于采用了这种方法,我们不需要任何自定义编译器,即使在系统中,可变参数函数的参数部分通过寄存器传递,部分通过堆栈传递(这是 PPC 和 x86_64 的情况,这也是 OS4 和 MOS 都需要专门修补编译器的原因)。

由于 NewObject 是一个宏,gcc 的预处理器期望宏参数列表用括号括起来。在 MUI 宏中情况并非如此。

ASL 请求器
[编辑 | 编辑源代码]

这应该 帮助

struct FileRequester *req;

if ((req=MUI_AllocAslRequestTags(ASL_FileRequest,
ASLFR_Window,win ,
ASLFR_TitleText, "A requester for AmiDevCpp",
ASLFR_InitialDrawer , "T:",
ASLFR_InitialFile, "foo.txt",
ASLFR_InitialPattern , "#?.txt",
ASLFR_DoPatterns , TRUE,
ASLFR_RejectIcons , TRUE,
TAG_DONE))) {

if (MUI_AslRequestTags(req,TAG_DONE)) {
/* you can find the drawer in req->fr_Drawer and the file in req->fr_File */
}
}

MUI_AslRequest() 函数和 MUI 会为您处理窗口刷新。

MUIA_Popasl_Active
MUIA_Popasl_StartHook
MUIA_Popasl_StopHook
MUIA_Popasl_Type

弹出式笔等

[编辑 | 编辑源代码]

MUIA_Window 或 MUIA_WindowObject?MUIA_Window 应该引用 struct Window *,而 MUIA_WindowObject 应该引用 Object *。

对于弹出式列表,无论打开还是关闭,这两个值始终为 NULL。

一个有趣的是,提供给 MUIA_Popobject_WindowHook 的窗口对象指针不是 NULL。检查弹出窗口是否打开,这样是否可以避免这种方法?弹出窗口对象只在用户点击弹出按钮且弹出窗口对象出现在屏幕上时打开——任何点击都会导致弹出窗口对象消失。所以,我甚至无法想象你在哪里以及为什么要检查这个。从第二个并行运行的任务?

如果弹出窗口对象是由您创建的,那么您始终可以对任何 MUI 类进行子类化。这样,您将获得所有方法和属性,例如 f.e. OM_SET/OM_GET 和 MUIM_Setup/MUIM_Cleanup/MUIM_Show/MUIM_Hide。可能在显示/隐藏上监听可能有助于检查弹出窗口当前是否打开。如果您不是应用程序的所有者,而是制作监控软件,那么此方法可能也适用于其他 MUI 应用程序,但不是子类化获取和存储调度程序地址,而是放置您自己的调度程序地址,然后监听像上面那样的方法/属性,然后调用原始调度程序以将控制权返回给原始应用程序。

看起来 Popstring 为此任务提供了特殊的钩子

  • MUIA_Popstring_OpenHook
  • MUIA_Popstring_CloseHook

向上/向下键(通常)绑定到 Page Up/Down,如果列表视图尚未绘制一次,则没有页面尺寸。

DoMethod(PP_String, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, App_p, 2, MUIM_Application_ReturnID, RID_EXECUTE);

如果一个标签更改(对于给定对象),则通知观察 - MUIA_String_Acknowledge 是字符串类的标签(不是 Popph-string),并且针对字符串对象设置(因此更改)。所以通知必须在这个对象上,而不是容器(即 Popph)上。

或者获取指向内部字符串对象的指针,并在其上设置通知(并尝试避免 ReturnID ;-) ) 应该只是将 MUIM_Notify 转发给子对象,最好只在 OM_GET 对所讨论的标签返回 TRUE 时转发。也就是说,如果 OM_GET 对 Popph 对象本身(可能是 Area 类的标签)返回 TRUE,则保留通知,否则尝试查看哪个子对象支持它。或者,如果 Popph 引入两个新的方法,类似于 MUIM_Popph_NotifyString & List,可能更好。然后可以使用这两个方法中的任何一个在内部对象上设置通知。

如果您不希望用户配置笔的值(您通常希望这样做),那么使用 ObtainBestPenA() 并没有错——但避免将笔相关的东西放在 MUIM_Show/Hide 中,它应该是 MUIM_Setup/Cleanup,否则它会在每次调整窗口大小时重新分配笔。

如果您希望用户能够配置笔,那么您可以使用 Poppen 对象和 MUI_ObtainPen() 来实现——以下是 MUI_PopPen.Doc 中的一段代码。

无论如何,您不必关心此类的内部结构。只需像这样创建它

obj = MUI_NewObject(MUIC_Poppen, MUIA_CycleChain , 1, MUIA_Window_Title, "Followed Links Color", TAG_DONE);

在您的首选项窗口中的某个地方,一切都会正常。您可以使用 MUIA_Pendisplay_Spec 属性从 Poppen 对象获取/设置当前颜色。然后可以将生成的 struct MUI_SpenSpec 保存到首选项的某个地方,并用作 MUI_ObtainPen() 和 MUI_ReleasePen() 的参数。

以“rxxxxxxgxxxxxxbxxxxxx”的格式返回。MUI_ObtainPen() 中有 3 个参数 *mri、*spec 和 flags.l。

查看 libraries/mui.h,您将找到类似这样的宏 muiRenderInfo(),只需执行以下操作

mymri = muiRenderInfo(myobj);

并且应该具有有效的 MUI_RenderInfo,但此宏只能在 MUIM_Setup/MUIM_Cleanup 之间使用。

一个与字符串工具连接的 popobject。popobject 是一个列表视图。这样,在字符串工具中按向上/向下键将上下滚动列表视图(即使列表视图处于隐藏状态)?

MUIA_String_AttachedList -- (V4 ) [ISG], Object *
MUIA_Popobject_Follow
MUIA_Popobject_Light
MUIA_Popobject_Object
MUIA_Popobject_ObjStrHook
MUIA_Popobject_StrObjHook
MUIA_Popobject_Volatile
MUIA_Popobject_WindowHook
MUIA_Poplist_Array
MUIM_Popstring_Close
MUIM_Popstring_Open

MUIA_Popstring_Button
MUIA_Popstring_CloseHook
MUIA_Popstring_OpenHook
MUIA_Popstring_String
MUIA_Popstring_Toggle
  • (N)Floattext 已经完全与您使用列表所做的一样。它将长文本分割成单独的行,插入一些空格以产生对齐的文本,并显示它们。
  • 只读模式下的 TextEditor 类或多或少与 Floattext 相同,但能够应用不同的样式和颜色,而不是标准的 MUI 文本引擎。此外,它允许用户在读写模式下编辑文本。YAM 在这两种模式下都大量使用它来显示和编辑邮件。

只完成了 Text()。因此,区域的大小取决于实际默认字体的尺寸。使用 rp(obj)->Font,但在 AskMinMax 中,它似乎在第一次调用时,Font 尚未初始化。您可以使用 _font(obj) 来获取字体。如果您还需要一个 rastport,那么您可以暂时设置一个来进行您的计算。

struct RastPort rp;
InitRastPort(&rp);
SetFont(&rp, _font(obj));
WORD size = TextLength(&rp, "The Text", 8);

问题是文本不会保持正确的大小。它们要么散布在整个窗口中,要么挤到一个边缘,而我想要的只是它们保持在右侧,并且大小足以显示 6 个字符(只要可能)。MUIA_String_Maxlen 似乎没有效果,强行设置一个宽度也不合适,因为你永远不知道用户是否更喜欢使用 50 像素宽的字体。

使用标签 MUIA_FixWidthTxt。例如

str = StringObject, MUIA_FixWidthTxt, "0000000", End;

注意那里有 7 个字符:一个用于光标。使用本质上很宽的字符(阅读 MUI_Area.doc 就能明白为什么)。

它也可以通过使用 MUIA_Weight、weight 来解决。尝试将“MUIA_Weight, weight”组合用于字符串,并在字符串对象之前/之后放置矩形对象。

例如,要将小工具对齐到右侧

HGroup,
Child, RectangleObject, MUIA_Weight, 75, End,
Child, StringObject,...,MUIA_Weight, 25, End,
End,

这意味着如果您想使用一个属性来更改标签和键盘快捷键,您应该对文本进行子类化,并处理一个用于更改标签和快捷键的特定标签,自行解析字符串。子类化 mui 类的示例可以在 mui dev kit 中找到(尤其是 psi 包含许多子类...),一些工具可以帮助您使用要子类化的类的元定义来创建骨架类(mui2c 或 bcc 可以执行此类操作)。

如果您创建一个类似于以下内容的子组

mygroup=Group ( MUIA_Group_PageMode,True
Child,SimpleButton("_Download"),
Child,SimpleButton("_Resume"),
TAG_DONE)

您会得到更好的结果。“下载”按钮现在可见,但如果您

set (mygroup, MUIA_Group_ActivePage, 1)

“下载”消失,“继续”变为可见。这是 MUI 应用程序中非常常见的技巧。

按钮只是文本对象,它们具有以下标签

MUIA_Text_SetVMax, TRUE

将其设置为 FALSE 会使 TextObjects 的 y 尺寸不受限制。默认值为 TRUE,这意味着对象的宽度是固定的。除非您将 MUIA_Text_SetVMax 设置为 FALSE(默认值为 TRUE),否则普通文本对象的高度不能高于其文本。这将使您的对象具有无限高度,但文本将垂直居中显示,除非您将 MUIA_Text_VCenter 设置为 FALSE。

MUIA_Text_Contents 是 ISG,因此

SetAttrs(text, MUIA_Text_Contents, "NewContent", TAG_DONE);
set (object->STR_text, MUIA_Text_Contents, myText);

object->STR_Text ? 看起来是 MUIBuilder 生成的代码 :)

如果您的“文本编辑框”是一个 String 对象,您最好使用

set( object->STR_text, MUIA_String_Contents, myText );

如何计算与 Move() 函数一起使用的 x/y 坐标,以便在使用 Text() 绘制标签时,标签显示在居中位置。mui.h 中有一堆宏。

_mleft() = starting x coordinate of your drawing area
_mtop() = starting y coord etc.
_mwidth() = width of your drawing area
_mheight() = obvious =)
text_height=GetItSomeHow();
text_len=TextLength("heipparallaa");

Move(rp, _mleft(obj) + ((_mwidth(obj) - text_len) / 2), _mtop(obj) + ((_mheight(obj) - text_height) / 2) );

(TextObject) 如果您确实需要更改文本,则必须在修改后再次设置它。

如果使用 TextObject,那么它具有完整的初始大小... 但是如果追加额外的行,那么这些行将不可见(虽然一个错误会导致它写到自身之外!)。获得其扩大以显示新文本的唯一方法是将 MUI 窗口图标化,然后取消图标化。此外,文本没有自动换行。

只要文本被对象“使用”,您就不得修改它。MUI 将根据给定的文本计算所需的尺寸,并期望它保持不变。如果您确实需要更改文本,则必须在修改后再次设置它。这将使 MUI 重新布局以显示所有新文本。

但这仅在一定程度上有效,即当整个文本的高度大于窗口的最大高度时。如果您需要显示更大的文本,则应该将对象放置在 Scrollgroup 对象中(其中一些与 MUI4 兼容),如下所示

ScrollgroupObject,
  MUIA_Scrollgroup_AutoBars, TRUE,
  MUIA_Scrollgroup_Contents, VGroupV,
    Child, TextObject,
      MUIA_Text_Contents, "insert your text here",
      MUIA_Text_Copy, TRUE,
      End,
    End,
  End,

属性 MUIA_Scrollgroup_AutoBars 将使滚动组仅在真正需要时显示滚动条,即内容的尺寸大于滚动组的尺寸。此属性仅在 MUI4 中可用,例如 MUIA_Text_Copy,MUI3 会静默忽略它,并且始终显示滚动条。

其次,属性 MUIA_Text_Copy 指示 Text.mui 保留文本的副本。这样就可以在对象创建后或 set() 后释放传递给 MUIA_Text_Contents 的文本,而且还可以修改文本,而不会在文本仍在修改时由于重绘操作而导致任何图形故障。

但是,您的文本始终会按照您指定的方式显示。这意味着您需要自己插入换行符。

如果使用 FloattextObject 或 TextEditorObject,那么无论初始内容如何,初始大小始终为三行文本(这是滚动条 + 箭头所需的最小空间),但至少可以垂直滚动。此外,文本会进行自动换行。

由于 Floattext.mui 会自己插入换行符,因此您不能期望可变高度,因为文本的高度取决于对象的高度。您可以通过使用类似 MUIA_FixHeightTxt,"\n\n\n\n" 的内容来强制执行特定对象高度。这将为您提供四行固定高度,同时尊重对象的字体。

Floattext.mui 是 List.mui 的子类,因此对它的尺寸没有限制,除非您强制执行,例如通过使用 MUIA_FixHeightTxt 或通过使用限制性实现 MUIM_AskMinMax 的子类化 Floattext.mui。MUI 不能简单地调整对象大小以显示整个初始内容,因为内容是任意的。它可能是零行,但也可能是百万行。在这种情况下,初始大小应该是什么?当然,您可以覆盖 MUIM_AskMinMax 并返回最适合您的尺寸,但您必须做好准备并接受 MUI 会在您的(或默认)MUIM_AskMinMax 方法返回的限制内调整对象的实际尺寸。

如果希望 Floattext 对象可调整大小,那么您还必须通过在标签对象的上方或下方添加至少一个空格对象来使标签可调整大小,例如

Child, VGroup, Child, Label2("FloattextObject"), Child, VSpace(0), End,

这将为您提供一个顶部对齐的标签。将标签放在 VSpace(0) 对象之后将使其底部对齐。使用 VCenter() 将为您提供一个垂直居中的标签。选择最适合您需求的解决方案。

查看 MUI 的演示应用程序 MUI-Demo。它在每个窗口中都使用 Floattext 对象。

MUIA_Text_Contents
MUIA_Text_PreParse
MUIA_Text_SetMax
MUIA_Text_SetMin
MUIA_Text_SetVMax

字体

[edit | edit source]

尝试在您的 MUIM_Draw 中放置 SetFont(_font(obj))。

在 OM_NEW 中,您应该将 MUIA_Font 设置为预定义值之一(MUIV_Font_XXXXXX 值),mui 将为您打开字体并使其可以使用 _font(obj) 访问。

在 MUIM_Draw 中,将 SetFont() 设置为我在 MUIM_Setup 中打开的字体。如果 SetFont(_font(obj)) 彻底丢失了用户可设置字体。您不允许直接更改 _rp( obj ) 的设置!因此请确保您正在处理原始光栅端口的副本,然后设置字体、颜色或其他任何内容。

struct RastPort rp1 = *_rp( obj );
struct RastPort *rp = &rp1;

SetAPen( rp, 0 );

对于正常的工具类 BOOPSI 对象,在绘制任何内容之前,您必须调用 ObtainGIRPort(),绘制,然后调用 ReleaseGIRPort()...

MUICFG_Font_Fixed

工具

[edit | edit source]

MUIM_Import/Export 并自行处理加载和保存。这样做的好处是,您无需为用户未访问的页面创建和调用 MUIM_Export,因为您将设置(来自已创建/访问的页面)导出到已填充的数据空间对象(在程序启动时加载)中,这应该可以节省时间、内存和复杂性。另一个好处是,它使添加“恢复默认值”、“恢复”等选项变得非常容易。

两个函数可以使将 IFF 文件保存/读取到数据空间对象变得更加容易。

VOID LoadDataspace (STRPTR file, Object *dataspace)
{
BPTR fh;
if(fh = Open(file, MODE_OLDFILE))
{
struct IFFHandle *iff;
if(iff = AllocIFF())
{
InitIFFasDOS(iff);
iff->iff_Stream = (ULONG)fh;
if(!OpenIFF(iff, IFFF_READ))
{
if(!StopChunk(iff, 'PREF', 'IPRB'))
{
if(!ParseIFF(iff, IFFPARSE_SCAN))
DoMethod(dataspace, MUIM_Dataspace_ReadIFF, iff);
}
CloseIFF(iff);
}
FreeIFF(iff);
}
Close(fh);
}
}
VOID SaveDataspace (STRPTR file, Object *dataspace, Object *app)
{
BOOL retry;
do {

retry = FALSE;
BPTR fh;
if(fh = Open(file, MODE_NEWFILE))
{
struct IFFHandle *iff;
if(iff = AllocIFF())
{
InitIFFasDOS(iff);
iff->iff_Stream = (ULONG)fh;
if(!OpenIFF(iff, IFFF_WRITE))
{
if(!PushChunk(iff, 'PREF', 'FORM', IFFSIZE_UNKNOWN))
DoMethod(dataspace, MUIM_Dataspace_WriteIFF, iff, 0, 'IPRB');

CloseIFF(iff);
}
FreeIFF(iff);
}
Close(fh);
}
else
{
UBYTE buf[84];
Fault(IoErr(), "DOS", buf, 84);
retry = MUI_Request(app, NULL, 0L, "Error", "_Retry|_Cancel", "\33cError saving:\n%s\n\n%s", file, buf);
}

} while(retry);
}

一个对象不能属于两个父对象。

如何确保分配了空闲笔?我在 16 位屏幕上运行大多数应用程序。我不确定需要什么,但我认为应该有一些方法可以获得一些空闲笔。如何“释放”笔?在真彩色/高彩色屏幕上,您可能希望拥有无限数量的空闲笔(或至少 65536/16777216 支笔),因为您可以更改每个像素的颜色而不会影响其他像素。但不幸的是,所有 RastPort 渲染函数都依赖于笔方案,RastPort 中的笔字段只有 8 位宽。这只会为您提供 256 支笔。

尝试使用 MUIA_Bitmap_SourceColors 和 MUIA_Bitmap_Precision,但我得到的只是一个黑色矩形,而不是变色的图像。您是否将 MUIA_Bodychunk_Depth 设置为 5,并将 MUIA_Bodychunk_Masking 设置为 0(但请检查您是否保存了 *没有* 掩码平面的画笔)?请记住,您应该在长字的每个字节中重复 R、G、B 值,例如,一些颜色,如 R=$A5,G=$32,B=$0A,在调色板数据中看起来像 $A5A5A5A5,$32323232,$0A0A0A0A。因此,每个调色板条目占用 12 个字节。

您需要在窗口上设置 MUIA_Window_UseBottomBorderScroller(或您想要的任何边)。然后创建属性对象并将 MUIA_Prop_UseWinBorder 设置为您在窗口中设置的相应边。然后只需在属性对象上设置一个通知以侦听 MUIA_Prop_First 中的更改。当您将一个放置在右侧并打开窗口时,MUI 会以最小的尺寸打开窗口,并且不会绘制窗口中应该存在的任何其他对象。

dtpic 数据类型

[edit | edit source]

如果您想获取包含图片数据的位图的指针或将其复制到您自己的位图的方法,但所有 Zune 属性均不起作用。

在这种情况下,您将希望直接使用 datatypes.library。据我所知,Dtpic 只是为了轻松地将数据类型图像包含到 MUI/Zune GUI 中(作为按钮图像,在列表视图中等等)。

如果 AROS 支持超级位图窗口刷新方法,那么您可以这样做。对于无边框窗口,您可能还想将其设为 gimmezerozero (gzz),以便边框和窗口内容具有单独的层(使用略多一点内存)。话虽如此,将位图直接绘制到窗口中可能是一个更简单、更便携的解决方案。

如何“转换”例如 png 图像为位图结构(数据类型)。DTpic.mui 是您的朋友。使用 picture.datatype,然后在 MUIM_Draw 中将位图绘制到对象光栅端口。

Child, image_button = MakeButton("PROGDIR:Imagesg/test_but.png", 't',"\33uT\33nest Button"),

static APTR MakeButton(UBYTE *Image, UBYTE Key, UBYTE *Help)
{
return(MUI_NewObject("Dtpic.mui",
MUIA_Dtpic_Name,Image,
MUIA_InputMode, MUIV_InputMode_RelVerify,
MUIA_ControlChar, Key,
MUIA_Background, MUII_ButtonBack,
MUIA_ShortHelp, Help,
PropFrame,TRUE,
ImageButtonFrame,
TAG_DONE));
}
if(app)
{
   struct BitMapHeader *bmhd;
   struct BitMap *bitmap;
   Object *datatype_obj;       /* pointer to the Datatype Object          */
   Object *bitmap_obj;         /* a mui BitmapObject                      */
   Object *list_obj;           /* the one that should be used in the list */

   if(datatype_obj = NewDTObject("Images/www.iff",
      DTA_SourceType , DTST_FILE,
      DTA_GroupID    , GID_PICTURE,
      TAG_DONE))
   {
      if(DoMethod(datatype_obj, DTM_PROCLAYOUT, NULL, 1))
      {
         get(datatype_obj, PDTA_BitMapHeader, &bmhd);
         GetDTAttrs(datatype_obj, PDTA_DestBitMap, &bitmap, TAG_DONE);
         if(!bitmap)
            GetDTAttrs(datatype_obj, PDTA_BitMap, &bitmap, TAG_DONE);

         if(bitmap_obj = BitmapObject,
            MUIA_Bitmap_SourceColors  , xget(datatype_obj, PDTA_CRegs),
            MUIA_Bitmap_Width         , bmhd->bmh_Width,
            MUIA_Bitmap_Height        , bmhd->bmh_Height,
            MUIA_FixWidth             , bmhd->bmh_Width,
            MUIA_FixHeight            , bmhd->bmh_Height,
            MUIA_Bitmap_Transparent   , 0,
            MUIA_Bitmap_Bitmap        , bitmap,
            End)
         {
            list_obj = (Object *)DoMethod(LV_ButtonBank, MUIM_List_CreateImage, bitmap_obj, NULL);
         }
      }
   }
}

在 MUI4.0 中

Child, zoneimage = (Object *) MUI_NewObject(MUIC_Dtpic,
				MUIA_Dtpic_Name, "PROGDIR:resource/zone_local.png",
				TAG_DONE),
					
DEFSMETHOD(OWBWindow_UpdateZone)
{
	GETDATA;

	char *image;

	switch(msg->zone)
	{
		default:
		case MV_OWBBrowser_Zone_Local:
			image = "PROGDIR:resource/zone_local.png";
			break;
		case MV_OWBBrowser_Zone_Internet:
			image = "PROGDIR:resource/zone_internet.png";
			break;
	}

	set(data->zoneimage, MUIA_Dtpic_Name, image);

	return 0;
}

例如,默认情况下,我们设置 zone_local 图像,然后通过通知调用 updatezone 来设置属性。它应该会发生变化(我的意思是图像),但实际上并没有变化。我看到我是在 Zone_Internet 中(通过 printfs),但图像没有设置。3.9 中存在问题。

移除

[edit | edit source]
void ExitClasses(void)
{
    if (NewList)
	{
        MUI_DeleteCustomClass(NewList);
		NewList = NULL;
	}
}

BOOL InitClasses(void)
{
    NewList = MUI_CreateCustomClass(NULL,MUIC_NList ,NULL,sizeof(struct NewList_Data),&NewList_Dispatcher);

	if (NewList) return(TRUE);
	else        return FALSE;
}

另一件事,您的编译器应该立即注意到,MyCustomClass 是 struct IClass *,将 Object * 分配给它是非常错误的,应该在 MUI_DeleteCustomClass() 时导致崩溃...

#define MyCustomObject NewObject(MyCustomClass->mcc_Class,NULL,

Object *mycustomobject;
mycustomobject = MyCustomObject, End;
if( mycustomobject != NULL )
{
app = ApplicationObject, [... ]
End;
if( app != NULL )
{
[...]
MUI_DisposeObject( app );
}
MUI_DisposeObject( mycustomobject );
}

或者,您最好对 Application.mui 类进行子类化,并在其中进行不可见的代码操作... 我认为这是处理它的最佳方法... 这样,主程序代码将几乎不受影响,并且可以在几秒钟内恢复使用标准 Application.mui,只需将 MyApplicationObject 重命名为 ApplicationObject(始终定义此类宏,而不是直接编写 NewObject()!)

使用 OM_REMMEMBER 方法删除对象(当然必须使用父对象)。

参考资料

[edit | edit source]

http://alfie.altervista.org/rxmui/rxmuidoc/classes.html

http://amiga.sourceforge.net/amigadevhelp/phpwebdev.php

当单击其中一个修饰符键(Shift、Ctrl、Alt)时,另一个键应该具有相同的状态。我在回调函数中尝试了

BOOL shift = XGET(data->keybutton[96], MUIA_Pressed) |
XGET(data->keybutton[97], MUIA_Pressed);

NNSET(data->keybutton[96], MUIA_Pressed, shift);
NNSET(data->keybutton[97], MUIA_Pressed, shift);

按下键盘上的修饰符键应该与单击按钮的效果相同。因此,我添加了一个事件处理程序方法。到目前为止,它可以正常工作,因为按钮的视觉状态已经改变。问题是,该事件方法中的 SET(keyobj, MUIA_Pressed, state) 不会触发回调挂钩。

尝试使用 MUIA_Selected,而不是 MUIA_Pressed(这实际上只是一个用于通知的东西,而不是真正的属性)。您还需要更改代码逻辑,因为一旦选择了两个 SHIFT 按钮,就无法取消选择它们(“shift”变量将始终为 TRUE)。

使用非阻塞 recv() 进行网络连接,从一个任务开始,并使所有接口基于推送。也就是说,没有人会调用 recv(),而是当从套接字接收到数据时(数据到达时)调用 recv()。因此,在主循环中,您等待套接字和用户事件,并将这些事件分配给相应的接收器(后者的操作由 MUI 完成)。采用这种方法的原因是简化代码(消除使用信号量等锁定资源/数据的需要),以及因为发现生成任务会产生明显的开销(但您可以让一个网络管理器始终运行来解决此问题),更不用说如果您在 8 个套接字上接收数据(每个套接字都有自己的进程),那么您的程序将被表示为 9 个总任务,因此,如果另一个程序需要 CPU 时间,它将只获得 1/10 的时间,而您的程序将获得 9/10 的时间,除非您调整任务的优先级,但这样会带来其他问题。如果您接收到的数据需要以某种方式进行解析,您可能一开始会觉得不得不将解析器编写为状态机很烦人,但 IMO 这些状态机也有优点。例如,它使向数据流添加过滤器或动态创建虚拟数据变得非常容易...

你需要一个工作在非阻塞和异步模式下的套接字。这将防止GUI在访问网络时被锁定。另一个步骤是为bsdsocket分配信号位,并使用GetSocketEvent()来找出网络操作,而无需使用笨拙的select()或WaitSelect()函数。这样一来,只要网络信号被设置,你就可以在循环中调用GetSocketEvent()。GetSocketEvent()会返回套接字描述符ID和可能发生的事件。要避免GetSocketEvent()及其类似函数,就好像它们是鼠疫一样!事实证明,它只在Miami下有效。虽然AmiTCP复制了M$的API,但它从未正常工作过。在你的MUI主循环中使用WaitSelect()代替Wait()。参见STRICQ 2源代码。如何从套接字接收数据?有没有办法将信号与套接字关联?你可以使用SocketBaseTags()将信号与套接字关联。在STRICQ v2套接字代码中使用WaitSelect()。但在v1中,使用了信号。

你可以在MUI应用程序子类中封装互联网客户端,创建一些有用的方法和属性,比如MUIM_NetApplication_Connect/Disconnect/Send/Receive,然后当用户按下连接/断开连接按钮时,在通知或回调函数中调用这些方法(因此,如果NetApplication连接成功,你将禁用连接,并启用断开连接等工具)。等等。永远不要在OM_NEW中立即连接到互联网,这将是愚蠢的,就像在那里创建必要的子进程一样(从另一方面来说,这可能不是一个好主意)。它可以等待,直到应用程序发送连接信号或消息,然后完成它的网络工作,直到它收到MUIM_NetApplication_Disconnect方法。如何...将bsdsocket.library和muimaster.library合并到一个漂亮的OOP应用程序中。

/*
    Copyright © 2002, The AROS Development Team.
    All rights reserved.

    $Id: aircos_server_gui.c 30794 2009-03-08 02:19:07Z neil $
*/

//#include    <exec/types.h>
#include    <stdlib.h>
#include    <stdio.h>
#include    <string.h>

#include    <proto/alib.h>
#include    <proto/exec.h>
#include    <proto/dos.h>
#include    <proto/intuition.h>
#include    <proto/muimaster.h>
#include    <proto/utility.h>

#include    <dos/dos.h>
#include    <intuition/gadgetclass.h>
#include    <intuition/icclass.h>
#include    <clib/alib_protos.h>

#include <libraries/mui.h>
#include <mui/NListtree_mcc.h>
#include <mui/NListview_mcc.h>
#include <mui/NList_mcc.h>

#include "aircos_global.h"
#include "locale.h"

extern struct AiRcOS_internal *AiRcOS_Base;
struct List                   aircos_Prefs_ServerNetworks;
struct List                   aircos_Prefs_Servers;
struct aircos_servernode      *aircos_Prefs_ServerActive;
struct Hook                   aircos_serversave_hook;
struct Hook                   aircos_networklistupdate_hook;
struct Hook                   aircos_serverlistupdate_hook;
struct Hook                   aircos_chooseserver_hook;

BOOL                          aircos_Prefs_ServersLoaded = FALSE;

Object	                     *input_server_address = NULL;
Object	                     *input_server_port =  NULL;
Object	                     *input_server_description =  NULL;
Object	                     *input_server_network =  NULL;
Object	                     *input_server_pass =  NULL;

Object                        *select_dropboxgrp_network = NULL;
Object                        *select_dropbox_network = NULL;
Object                        *select_dropboxgrp_server = NULL;
Object                        *select_dropbox_server = NULL;

STRPTR	                     network_list_empty[2] =
{
  {"<List Empty>"},
  NULL
};
STRPTR	                     server_list_empty[2] =
{
  {"<List Empty>"},
  NULL
};
Object	                     *servermodWin;
STRPTR	                     *network_list;
STRPTR	                     *server_list;

//network_list_empty[0] = "<List Empty>";		//MSG(MSG_LIST_EMPTY);
//network_list_empty[1] = NULL;

//server_list_empty[0] = "<List Empty>";		//MSG(MSG_LIST_EMPTY);
//server_list_empty[1] = NULL;

#define AIRCOS_DEF_SERVERSFILE "servers.dat"

aircosApp_LoadServers()
{
  aircos_Prefs_ServersLoaded = TRUE;
}

struct aircos_networknode *aircosApp_FindServerNetworkNode(char * findNetwork)
{
  struct aircos_networknode *current_Node = NULL;
  ForeachNode(&aircos_Prefs_ServerNetworks, current_Node)
  {
D(bug("[AiRcOS](FindServerNetworkNode) Checking against record for '%s'\n", current_Node->ann_Network));
      if (strcasecmp(current_Node->ann_Network, findNetwork)==0) return current_Node;
  }
  return NULL;
}

struct aircos_servernode  *aircosApp_FindServerNode(char * findServer)
{
struct aircos_servernode  *current_Node = NULL;
  ForeachNode(&aircos_Prefs_Servers, current_Node)
  {
D(bug("[AiRcOS](FindServerNode) Checking against record for '%s'\n", current_Node->asn_Server));
      if (strcasecmp(current_Node->asn_Server, findServer)==0) return current_Node;
  }
  return NULL;
}

AROS_UFH3(void, chooseserver_func,
   AROS_UFHA(struct Hook *, unused_hook, A0),
   AROS_UFHA(APTR, obj, A2),
   AROS_UFHA(struct IRC_Channel_Priv  *, hook_channel_arg, A1 ))
{
   AROS_USERFUNC_INIT
D(bug("[AiRcOS] chooseserver_func()\n"));
  ULONG                      currentPrefsServerID;
  get(select_dropbox_server, MUIA_Cycle_Active, &currentPrefsServerID);

  struct aircos_servernode *currentPrefsServer = NULL;
  if (!(currentPrefsServer = aircosApp_FindServerNode(server_list[currentPrefsServerID])))
  {
D(bug("[AiRcOS] chooseserver_func: Couldnt find Server Node!\n"));
    return;
  }

  aircos_Prefs_ServerActive = currentPrefsServer;

  AROS_USERFUNC_EXIT
};

AROS_UFH3(void, updatenetworklist_func,
   AROS_UFHA(struct Hook *, unused_hook, A0),
   AROS_UFHA(APTR, obj, A2),
   AROS_UFHA(struct IRC_Channel_Priv  *, hook_channel_arg, A1 ))
{
   AROS_USERFUNC_INIT
D(bug("[AiRcOS] updatenetworklist_func()\n"));
  struct aircos_networknode *currentPrefsNetwork = NULL;
  ULONG                      prefsNetworkCount = 0;
  ULONG                      setprefsNetworkActive = 0;
  Object                     *new_dropbox_network = NULL;
  
  ForeachNode(&aircos_Prefs_ServerNetworks, currentPrefsNetwork)
  {
      prefsNetworkCount++;
      if (aircos_Prefs_ServerActive)
        if (strcasecmp(currentPrefsNetwork->ann_Network, aircos_Prefs_ServerActive->asn_Network->ann_Network)==0)
        {
          setprefsNetworkActive = prefsNetworkCount -1;
        }
  }

D(bug("[AiRcOS] updatenetworklist_func: %d network nodes\n", prefsNetworkCount));
  
  if (prefsNetworkCount > 0)
  {
    if (network_list != network_list_empty) {
      FreeVec(network_list);
    }
    
    if ((network_list = AllocVec(sizeof(IPTR) * prefsNetworkCount+1, MEMF_CLEAR|MEMF_PUBLIC)))
    {
      int loop_count = 0;

      ForeachNode(&aircos_Prefs_ServerNetworks, currentPrefsNetwork)
      {
        network_list[loop_count] = currentPrefsNetwork->ann_Network;
        loop_count++;
      }
    }
    else
    {
D(bug("[AiRcOS] updatenetworklist_func: ERROR - couldnt allocate memory for network name pointer table\n"));
      network_list = network_list_empty;
    }
  } else if (network_list != network_list_empty) {
    FreeVec(network_list);
    network_list = network_list_empty; 
  }

  if (!(new_dropbox_network = MUI_MakeObject(MUIO_Cycle, NULL, network_list)))
  {
D(bug("[AiRcOS] updatenetworklist_func: Failed to create Network dropdown\n"));
    return NULL;
  }

  if (DoMethod(select_dropboxgrp_network, MUIM_Group_InitChange))
  {
    DoMethod(select_dropboxgrp_network, OM_REMMEMBER, select_dropbox_network);
    DoMethod(select_dropboxgrp_network, OM_ADDMEMBER, new_dropbox_network);
    DoMethod(select_dropboxgrp_network, MUIM_Group_ExitChange);
    select_dropbox_network = new_dropbox_network;
  }

  DoMethod(select_dropbox_network, MUIM_NoNotifySet, MUIA_Cycle_Active, setprefsNetworkActive);
  DoMethod
  (
      select_dropbox_network, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime,
      (IPTR) AiRcOS_Base->aircos_app, 3, MUIM_CallHook, &aircos_serverlistupdate_hook, NULL
  );
        
  AROS_USERFUNC_EXIT
};

AROS_UFH3(void, updateserverlist_func,
   AROS_UFHA(struct Hook *, unused_hook, A0),
   AROS_UFHA(APTR, obj, A2),
   AROS_UFHA(struct IRC_Channel_Priv  *, hook_channel_arg, A1 ))
{
   AROS_USERFUNC_INIT
D(bug("[AiRcOS] updateserverlist_func()\n"));
  struct aircos_servernode   *currentPrefsServer = NULL;
  ULONG                      prefsNetworkServerCount = 0;
  ULONG                      setprefsServerActive = 0;
  Object                     *new_dropbox_server = NULL;

  ULONG                      currentPrefsNetworkID;
  get(select_dropbox_network, MUIA_Cycle_Active, &currentPrefsNetworkID);

  struct aircos_networknode *currentPrefsNetwork = NULL;
  if (!(currentPrefsNetwork = aircosApp_FindServerNetworkNode(network_list[currentPrefsNetworkID])))
  {
D(bug("[AiRcOS] updateserverlist_func: Couldnt find Network Node!\n"));
    return;
  }

  ForeachNode(&aircos_Prefs_Servers, currentPrefsServer)
  {
      if (strcasecmp(currentPrefsServer->asn_Network->ann_Network, currentPrefsNetwork->ann_Network)==0)
      {
        prefsNetworkServerCount++;
        if (aircos_Prefs_ServerActive)
          if (strcasecmp(currentPrefsServer->asn_Server, aircos_Prefs_ServerActive->asn_Server)==0)
          {
            setprefsServerActive = prefsNetworkServerCount -1;
          }
      }
  }

D(bug("[AiRcOS] updateserverlist_func: %d server nodes for network '%s'\n", prefsNetworkServerCount, currentPrefsNetwork->ann_Network));
  
  if (prefsNetworkServerCount > 0)
  {
    if (server_list != server_list_empty) {
      FreeVec(server_list);
    }
    
    if ((server_list = AllocVec(sizeof(IPTR) * prefsNetworkServerCount+1, MEMF_CLEAR|MEMF_PUBLIC)))
    {
      int loop_count = 0;

      ForeachNode(&aircos_Prefs_Servers, currentPrefsServer)
      {
        if (strcasecmp(currentPrefsServer->asn_Network->ann_Network, currentPrefsNetwork->ann_Network)==0)
        {
          server_list[loop_count] = currentPrefsServer->asn_Server;
          loop_count++;
        }
      }
    }
    else
    {
D(bug("[AiRcOS] updateserverlist_func: ERROR - couldnt allocate memory for server name pointer table\n"));
      server_list = server_list_empty;
    }
  } else if (server_list != server_list_empty) {
    FreeVec(server_list);
    server_list = server_list_empty; 
  }

  if (!(new_dropbox_server = MUI_MakeObject(MUIO_Cycle, NULL, server_list)))
  {
D(bug("[AiRcOS] updateserverlist_func: Failed to create Server dropdown\n"));
    return NULL;
  }

  if (DoMethod(select_dropboxgrp_server, MUIM_Group_InitChange))
  {
    DoMethod(select_dropboxgrp_server, OM_REMMEMBER, select_dropbox_server);
    DoMethod(select_dropboxgrp_server, OM_ADDMEMBER, new_dropbox_server);
    DoMethod(select_dropboxgrp_server, MUIM_Group_ExitChange);
    select_dropbox_server = new_dropbox_server;
  }

  DoMethod(select_dropbox_server, MUIM_NoNotifySet, MUIA_Cycle_Active, setprefsServerActive);

  AROS_USERFUNC_EXIT
};

AROS_UFH3(void, serversave_func,
   AROS_UFHA(struct Hook *, unused_hook, A0),
   AROS_UFHA(APTR, obj, A2),
   AROS_UFHA(struct IRC_Channel_Priv  *, hook_channel_arg, A1 ))
{
   AROS_USERFUNC_INIT
D(bug("[AiRcOS] serversave_func()\n"));

  struct aircos_networknode *newsaveNetwork = NULL;
  char                      *newsaveNetwork_name;
  BOOL                      newsaveNetwork_update = FALSE;

  struct aircos_servernode  *newsaveServer = NULL;
  char                      *newsaveServer_name;
  BOOL                      newsaveServer_update = FALSE;

   get( input_server_network, MUIA_String_Contents, &newsaveNetwork_name);
   get( input_server_address, MUIA_String_Contents, &newsaveServer_name);

  if (!(newsaveNetwork = aircosApp_FindServerNetworkNode(newsaveNetwork_name)))
  {
D(bug("[AiRcOS](serversave_func) created new network node for '%s'\n", newsaveNetwork_name));
     newsaveNetwork = AllocVec(sizeof(struct aircos_networknode), MEMF_CLEAR|MEMF_PUBLIC);
     newsaveNetwork->ann_Network = AllocVec(strlen(newsaveNetwork_name)+1, MEMF_CLEAR|MEMF_PUBLIC);
     CopyMem(newsaveNetwork_name, newsaveNetwork->ann_Network, strlen(newsaveNetwork_name)+1);

     AddTail((struct List *)&aircos_Prefs_ServerNetworks, (struct Node *)&newsaveNetwork->ann_Node);
     newsaveNetwork_update = TRUE;
  }
  newsaveNetwork->ann_ServerCount += 1;
D(bug("[AiRcOS](serversave_func) %s Network node server count = %d\n", newsaveNetwork->ann_Network, newsaveNetwork->ann_ServerCount));

  if (!(newsaveServer = aircosApp_FindServerNode(newsaveServer_name)))
  {
D(bug("[AiRcOS](serversave_func) created new server node for '%s'\n", newsaveServer_name));
     newsaveServer = AllocVec(sizeof(struct aircos_servernode), MEMF_CLEAR|MEMF_PUBLIC);
     newsaveServer->asn_Server = AllocVec(strlen(newsaveServer_name)+1, MEMF_CLEAR|MEMF_PUBLIC);
     CopyMem(newsaveServer_name, newsaveServer->asn_Server, strlen(newsaveServer_name)+1);
     newsaveServer->asn_Network = newsaveNetwork;
     get( input_server_port, MUIA_String_Integer, &newsaveServer->asn_Port);

#warning "TODO: we need to store the password also here .."

     AddTail((struct List *)&aircos_Prefs_Servers, (struct Node *)&newsaveServer->asn_Node);
     newsaveServer_update = TRUE;
  }
  else
  {
D(bug("[AiRcOS](serversave_func) node already exists for server '%s'\n", newsaveServer_name));
  }

  aircos_Prefs_ServerActive = newsaveServer;

  set( servermodWin, MUIA_Window_Open, FALSE);

  if (newsaveNetwork_update) CallHookPkt(&aircos_networklistupdate_hook, obj, hook_channel_arg);
  if (newsaveServer_update) CallHookPkt(&aircos_serverlistupdate_hook, obj, hook_channel_arg);

  AROS_USERFUNC_EXIT
};

Object	*aircos_showServerConnect()
{
D(bug("[AiRcOS] showServerConnect()\n"));
  if (aircos_Prefs_ServersLoaded)
  {
D(bug("[AiRcOS](showServerConnect) Server windows already configured!\n"));
    return NULL;
  }

   Object   *tmp_connectWin = NULL;

  NewList((struct List *)&aircos_Prefs_ServerNetworks);
  NewList((struct List *)&aircos_Prefs_Servers);

	Object	*butt_addServer = NULL;
	Object	*butt_editServer = NULL;
	Object	*butt_delServer = NULL;
	Object	*butt_serverConnect = NULL;
	Object   *butt_serverSave = NULL;

   network_list = network_list_empty;
   server_list = server_list_empty;

	if (!(select_dropbox_network = MUI_MakeObject(MUIO_Cycle, NULL, network_list)))
	{
D(bug("[AiRcOS](showServerConnect) Failed to create Network dropdown\n"));
      return NULL;
	}
	
	if (!(select_dropbox_server = MUI_MakeObject(MUIO_Cycle, NULL, server_list)))
	{
D(bug("[AiRcOS](showServerConnect) Failed to create Server dropdown\n"));
      return NULL;
	}

   if (!(butt_addServer = SimpleButton("Add")))
	{
D(bug("[AiRcOS](showServerConnect) Failed to create 'ADD' button\n"));
      return NULL;
	}
	
   if (!(butt_editServer = SimpleButton("Edit")))
	{
D(bug("[AiRcOS](showServerConnect) Failed to create 'EDIT' button\n"));
      return NULL;
	}
	
   if (!(butt_delServer = SimpleButton("Del")))
	{
D(bug("[AiRcOS](showServerConnect) Failed to create 'DEL' button\n"));
      return NULL;
	}

   if (!(butt_serverConnect = SimpleButton("Connect!")))
	{
D(bug("[AiRcOS](showServerConnect) Failed to create 'CONNECT' button\n"));
      return NULL;
	}

   if (!(butt_serverSave = SimpleButton("Save!")))
	{
D(bug("[AiRcOS](showServerConnect) Failed to create 'SAVE' button\n"));
      return NULL;
	}

   select_dropboxgrp_network = VGroup,
                                 Child, (IPTR) select_dropbox_network,
                               End;

   select_dropboxgrp_server = VGroup,
                                Child, (IPTR) select_dropbox_server,
                              End;

	tmp_connectWin = WindowObject,
            MUIA_Window_Title, (IPTR) "Connect to Server..",
            MUIA_Window_Activate, TRUE,
            MUIA_Window_Width,200,
            MUIA_Window_Height,200,
     
            WindowContents, (IPTR) VGroup,
                Child, (IPTR) HGroup,
                  GroupFrame,
					   Child, (IPTR) VGroup,
						  Child, (IPTR) LLabel("IRC Network"),
						  Child, (IPTR) HGroup,
						    Child, (IPTR) HSpace(0),
						    Child, (IPTR) select_dropboxgrp_network,
						    Child, (IPTR) HSpace(0),
						  End,
					   End,
					   Child, (IPTR) HVSpace,
                End,
                Child, (IPTR) HGroup,
                  GroupFrame,
					   Child, (IPTR) VGroup,
						  Child, (IPTR) LLabel("IRC Server"),
						  Child, (IPTR) HGroup,
						    Child, (IPTR) HVSpace,
						    Child, (IPTR) select_dropboxgrp_server,
						    Child, (IPTR) HVSpace,
						  End,
					   End,
  					   Child, (IPTR) HVSpace,
                End,
                Child, (IPTR) HGroup,
					   Child, (IPTR) HVSpace,
					   Child, (IPTR) butt_addServer,
					   Child, (IPTR) butt_editServer,
					   Child, (IPTR) butt_delServer,
                End,
                Child, (IPTR) butt_serverConnect,
            End,
        End;

	servermodWin = WindowObject,
        
            MUIA_Window_Title, (IPTR) "Edit Server..",
            MUIA_Window_Activate, TRUE,
            MUIA_Window_Width,350,
            MUIA_Window_Height,400,
     
            WindowContents, (IPTR) VGroup,
               Child, (IPTR) VGroup,
                 GroupFrame,
                 Child, (IPTR) HGroup,
					    Child, (IPTR) LLabel("IRC Server Address"),
					    Child, (IPTR) (input_server_address = StringObject,
										StringFrame,
                              MUIA_CycleChain, TRUE,
										MUIA_String_Format, MUIV_String_Format_Right,
                   End ),
                 End,
                 Child, (IPTR) HGroup,
					    Child, (IPTR) LLabel("Port"),
					    Child, (IPTR) (input_server_port = StringObject,
										StringFrame,
                              MUIA_CycleChain, TRUE,
										MUIA_String_Format, MUIV_String_Format_Right,
										MUIA_String_Accept, "0123456789",
										MUIA_String_Integer, 0,
					    End),
                 End,
                 Child, (IPTR) HGroup,
					    Child, (IPTR) LLabel("Server Description"),
					    Child, (IPTR) (input_server_description = StringObject,
										StringFrame,
                              MUIA_CycleChain, TRUE,
										MUIA_String_Format, MUIV_String_Format_Right,
					    End),
                 End,
                 Child, (IPTR) HGroup,
					    Child, (IPTR) LLabel("IRC Network"),
					    Child, (IPTR) (input_server_network = StringObject,
										StringFrame,
                              MUIA_CycleChain, TRUE,
										MUIA_String_Format, MUIV_String_Format_Right,
					    End),
                 End,
               End,
               Child, (IPTR) VGroup,
                 GroupFrame,
				     Child, (IPTR) LLabel("Enter server password here if applicable."),
                 Child, (IPTR) HGroup,
					    Child, (IPTR) LLabel("Password"),
					    Child, (IPTR) (input_server_pass = StringObject,
										StringFrame,
                              MUIA_CycleChain, TRUE,
										MUIA_String_Format, MUIV_String_Format_Right,
					    End),
                 End,
               End,
               Child, (IPTR) butt_serverSave,
            End,
        End;

	if ((tmp_connectWin)&&(servermodWin))
	{
D(bug("[AiRcOS](showServerConnect) Created GUI objects\n"));
      DoMethod
        (
            AiRcOS_Base->aircos_app, OM_ADDMEMBER,
            (IPTR) tmp_connectWin
        );

      DoMethod
        (
            AiRcOS_Base->aircos_app, OM_ADDMEMBER,
            (IPTR) servermodWin
        );

        DoMethod
        (
            tmp_connectWin, MUIM_Notify, MUIA_Window_Open, TRUE,
            (IPTR) AiRcOS_Base->aircos_quickconnectwin, 3, MUIM_Set, MUIA_Window_Open, FALSE
        );

        DoMethod
        (
            AiRcOS_Base->aircos_quickconnectwin, MUIM_Notify, MUIA_Window_Open, TRUE,
            (IPTR) tmp_connectWin, 3, MUIM_Set, MUIA_Window_Open, FALSE
        );

        DoMethod
        (
            tmp_connectWin, MUIM_Notify, MUIA_Window_Open, FALSE,
            (IPTR) servermodWin, 3, MUIM_Set, MUIA_Window_Open, FALSE
        );

      DoMethod
        (
            butt_addServer, MUIM_Notify, MUIA_Selected, FALSE,
            (IPTR) servermodWin, 3, MUIM_Set, MUIA_Window_Open, TRUE
        );

      DoMethod
        (
            butt_editServer, MUIM_Notify, MUIA_Selected, FALSE,
            (IPTR) servermodWin, 3, MUIM_Set, MUIA_Window_Open, TRUE
        );

//      DoMethod
//        (
//            butt_delServer, MUIM_Notify, MUIA_Selected, FALSE,
//            (IPTR) servermodWin, 3, MUIM_Set, MUIA_ShowMe, FALSE
//        );

        DoMethod
        (
            tmp_connectWin, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
            (IPTR) tmp_connectWin, 3, MUIM_Set, MUIA_Window_Open, FALSE
        );
        
        DoMethod
        (
            servermodWin, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
            (IPTR) servermodWin, 3, MUIM_Set, MUIA_Window_Open, FALSE
        );

        DoMethod
        (
            butt_serverConnect, MUIM_Notify, MUIA_Pressed, FALSE,
                (IPTR) AiRcOS_Base->aircos_app, 3, MUIM_CallHook, &AiRcOS_Base->aircos_connect_hook, NULL
        );

D(bug("[AiRcOS](showServerConnect) prepare list update hooks\n"));
    
       aircos_serversave_hook.h_MinNode.mln_Succ = NULL;
       aircos_serversave_hook.h_MinNode.mln_Pred = NULL;
       aircos_serversave_hook.h_Entry = HookEntry;
       aircos_serversave_hook.h_SubEntry = (void *)serversave_func;

       aircos_networklistupdate_hook.h_MinNode.mln_Succ = NULL;
       aircos_networklistupdate_hook.h_MinNode.mln_Pred = NULL;
       aircos_networklistupdate_hook.h_Entry = HookEntry;
       aircos_networklistupdate_hook.h_SubEntry = (void *)updatenetworklist_func;
       
       aircos_serverlistupdate_hook.h_MinNode.mln_Succ = NULL;
       aircos_serverlistupdate_hook.h_MinNode.mln_Pred = NULL;
       aircos_serverlistupdate_hook.h_Entry = HookEntry;
       aircos_serverlistupdate_hook.h_SubEntry = (void *)updateserverlist_func;

       aircos_chooseserver_hook.h_MinNode.mln_Succ = NULL;
       aircos_chooseserver_hook.h_MinNode.mln_Pred = NULL;
       aircos_chooseserver_hook.h_Entry = HookEntry;
       aircos_chooseserver_hook.h_SubEntry = (void *)chooseserver_func;

        DoMethod
        (
            butt_serverSave, MUIM_Notify, MUIA_Pressed, FALSE,
                (IPTR) AiRcOS_Base->aircos_app, 3, MUIM_CallHook, &aircos_serversave_hook, NULL
        );

        DoMethod
        (
            select_dropbox_network, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime,
                (IPTR) AiRcOS_Base->aircos_app, 3, MUIM_CallHook, &aircos_serverlistupdate_hook, NULL
        );

        DoMethod
        (
            select_dropbox_server, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime,
                (IPTR) AiRcOS_Base->aircos_app, 3, MUIM_CallHook, &aircos_chooseserver_hook, NULL
        );

D(bug("[AiRcOS](showServerConnect) Configured NOTIFICATIONS\n"));

       set(tmp_connectWin, MUIA_Window_Open, TRUE);
       D(bug("[AiRcOS](showServerConnect) Window opened ..\n"));
     }
     else
     {
      if (!(servermodWin))
      {
D(bug("[AiRcOS](showServerConnect) Failed to create server edit window..\n"));
      }
      else MUI_DisposeObject(servermodWin);
      
      if (!(tmp_connectWin))
      {
D(bug("[AiRcOS](showServerConnect) Failed to create server selection window..\n"));      
      }
      else MUI_DisposeObject(tmp_connectWin);
     }

	return tmp_connectWin;
}
/*
    Copyright © 2002, The AROS Development Team.
    All rights reserved.

    $Id: mini2.c 30792 2009-03-07 22:40:04Z neil $
*/

#include <exec/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <dos/dos.h>
#include <intuition/gadgetclass.h>
#include <intuition/icclass.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/muimaster.h>
#include <clib/alib_protos.h>

/* the following should go in a single include file which then only
** constits of the public constants and members. Actually this is easiey
*/

#include <libraries/mui.h>

#define DEBUG 1
#include <aros/debug.h>

Object *app;

int main(void)
{
    Object *wnd;
    static char *radio_entries2[] = {"Paris","London",NULL};

    app = ApplicationObject,
   	SubWindow, wnd = WindowObject,
    	    WindowContents, VGroup,
	Child, HGroup,
	    MUIA_InputMode, MUIV_InputMode_Immediate,
/*              MUIA_ShowSelState, FALSE, */
	    Child, ImageObject,
                MUIA_ShowSelState, FALSE,
	        MUIA_Image_FontMatch, TRUE,
	        MUIA_Image_Spec, MUII_RadioButton,
	        MUIA_Frame, MUIV_Frame_None,
   	        End,
	    Child, TextObject,
                MUIA_ShowSelState, FALSE,
	        MUIA_Text_Contents, "London",
	        MUIA_Frame, MUIV_Frame_None,
	        MUIA_Text_PreParse, "\33l",
	        End,
	End,
		End,
	    End,
	End;

    if (app)
    {
	ULONG sigs = 0;
/*  #if 0 */
	DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

/*  #endif */
	set(wnd, MUIA_Window_Open, TRUE);

/*  #if 0 */
	while((LONG) DoMethod(app, MUIM_Application_NewInput, &sigs) != MUIV_Application_ReturnID_Quit)
	{
	    if (sigs)
	    {
		sigs = Wait(sigs | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
		if (sigs & SIGBREAKF_CTRL_C) break;
		if (sigs & SIGBREAKF_CTRL_D) break;
	    }
	}
/*  #endif */
	set(wnd, MUIA_Window_Open, FALSE);
	MUI_DisposeObject(app);
    }
    
    return 0;
}
/*
    Copyright © 2002, The AROS Development Team.
    All rights reserved.

    $Id: dirlist.c 30792 2009-03-07 22:40:04Z neil $
*/

#include <exec/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <dos/dos.h>
#include <intuition/gadgetclass.h>
#include <intuition/icclass.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/muimaster.h>
#include <clib/alib_protos.h>

/* the following should go in a single include file which then only
** constits of the public constants and members. Actually this is easiey
*/

#include <libraries/mui.h>

struct Library *MUIMasterBase;

Object *app;

int main(void)
{
    Object *wnd, *str, *dirlist, *page;
    
    MUIMasterBase = (struct Library*)OpenLibrary("muimaster.library",0);

    app = ApplicationObject,
   	SubWindow, wnd = WindowObject,
    	    MUIA_Window_Title, "dirlist",
	    MUIA_Window_Activate, TRUE,

    	    WindowContents, VGroup,
	    	MUIA_Background, MUII_GroupBack,
		Child, ListviewObject,
		    MUIA_Listview_List, dirlist = DirlistObject,
    	    	    	InputListFrame,
		    	End,
		    End,
		Child, HGroup,
		    Child, str = StringObject,
			StringFrame,
			MUIA_String_Contents, (IPTR)"SYS:",
			End,
		    Child, page = PageGroup,
		    	MUIA_Weight, 0,
			MUIA_FixWidthTxt, (IPTR)"AA",
		    	Child, ColorfieldObject,
			    MUIA_Colorfield_Red, 0xFFFFFFFF,
			    MUIA_Colorfield_Green, 0,
			    MUIA_Colorfield_Blue, 0,
			    End,
		    	Child, ColorfieldObject,
			    MUIA_Colorfield_Red, 0xFFFFFFFF,
			    MUIA_Colorfield_Green, 0xFFFFFFFF,
			    MUIA_Colorfield_Blue, 0,
			    End,
		    	Child, ColorfieldObject,
			    MUIA_Colorfield_Red, 0,
			    MUIA_Colorfield_Green, 0x66666666,
			    MUIA_Colorfield_Blue, 0,
			    End,
		    	End,
		    End,
		End,
	    End,
	End;

    if (app)
    {
	ULONG sigs = 0;

	DoMethod
        (
            wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, (IPTR) app, 
            2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit
        );

    	DoMethod(str, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
	    	 (IPTR)dirlist, 3, MUIM_Set, MUIA_Dirlist_Directory, MUIV_TriggerValue);
		 
    	DoMethod(dirlist, MUIM_Notify, MUIA_Dirlist_Status, MUIV_EveryTime,
	    	 (IPTR)page, 3, MUIM_Set, MUIA_Group_ActivePage, MUIV_TriggerValue);
		 
    	set(dirlist, MUIA_Dirlist_Directory, "SYS:");
	
	set(wnd,MUIA_Window_Open,TRUE);

	while (DoMethod(app, MUIM_Application_NewInput, (IPTR) &sigs) != MUIV_Application_ReturnID_Quit)
	{
	    if (sigs)
	    {
		sigs = Wait(sigs | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
		if (sigs & SIGBREAKF_CTRL_C) break;
		if (sigs & SIGBREAKF_CTRL_D) break;
	    }
	}

	MUI_DisposeObject(app);
    }

    CloseLibrary(MUIMasterBase);
    
    return 0;
}

WaitSelect()需要一个指向你的信号掩码的指针。所以你需要做一些类似的操作

sigs |= SIGBREAKF_CTRL_C;
ret = WaitSelect(s+1, &rdfs, NULL, NULL, &sigs);

然后“sigs”应该包含Wait()通常返回的位。

/*
 * Amiga Generic Set - set of libraries and includes to ease sw development for all Amiga platforms
 * Copyright (C) 2004-2008 Tomasz Wiszkowski Tomasz.Wiszkowski at gmail.com.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "MUIPictureClass.h"
#include <Generic/LibrarySpool.h>
#include <libclass/intuition.h>
#include <libclass/muimaster.h>
#include <libraries/mui.h>
#include <libclass/utility.h>

using namespace GenNS;

#define __NOGLOBALIFACE__
#include <proto/graphics.h>

   static struct Library *GfxBase = 0;
#ifdef __AMIGAOS4__
   static struct GraphicsIFace *IGraphics = 0;
#endif

   MUICustomClassT<MUIPictureClass> *MUIPictureClass::muiclass = 0;
   static int            openCount = 0;

MUIPictureClass::MUIPictureClass(IClass *cls)
{
   openCount++;
   parent   = cls;
   image1   = "";
   image2   = "";
   width    = 64;
   height   = 48;
   dtimg1   = 0;
   dtimg2   = 0;
   dt       = DatatypesIFace::GetInstance(44);
   if (dt == 0)
   {
      request("Warning", "This program requires datatypes.library v44 or later\nGraphical buttons will not be displayed.", "Continue", 0);
   }

   if (GfxBase == 0)
   {
      GfxBase = Exec->OpenLibrary("graphics.library", 39);
   }
#ifdef __AMIGAOS4__
   if ((GfxBase != 0) && (IGraphics == 0))
   {
      IGraphics = (GraphicsIFace*)Exec->GetInterface(GfxBase, "main", 1, (TagItem*)NULL);
   }
#endif
}

MUIPictureClass::~MUIPictureClass()
{
   closeImages();
   dt->FreeInstance();
   openCount--;
   if (0 == openCount)
   {
#ifdef __AMIGAOS4__
      Exec->DropInterface((Interface*)IGraphics);
      IGraphics = 0;
#endif
      Exec->CloseLibrary(GfxBase);
      GfxBase = 0;
   }
}

iptr MUIPictureClass::DoMtd(iptr *obj, iptr *msg)
{
   uint16  *minmax;
   iptr      k;

   switch (msg[0]) 
   {
      case OM_NEW:
         {
            if (!(obj = (Object*)DoSuperMtd(parent, obj, msg))) 
               return 0;

            k = (iptr)Utility->GetTagData(MUIA_Picture_NormalImage, 0, (TagItem*)msg[1]);
            if (k != 0)
               image1 = (char*)k;
            k = (iptr)Utility->GetTagData(MUIA_Picture_SelectedImage, 0, (TagItem*)msg[1]);
            if (k != 0)
               image2 = (char*)k;

            isDisabled = Utility->GetTagData(MUIA_Disabled, 0, (struct TagItem*)msg[1]) ? true : false;
            isSelected = Utility->GetTagData(MUIA_Selected, 0, (struct TagItem*)msg[1]) ? true : false;

            openImages();

            return (ULONG)obj;
         }
         break;

      case OM_DISPOSE:
      case MUIM_Hide:
         break;
      
      case MUIM_Show:
         {
            if (dt != 0)
            {
               if (dtimg1 != 0)
               {
                  dt->SetDTAttrsA(dtimg1, 0, 0, (TagItem*)ARRAY(
                     PDTA_Screen,         (iptr)_screen(obj), 
                     PDTA_DestMode,       PMODE_V43, 
                     PDTA_UseFriendBitMap,true,
                     TAG_DONE,            0));

                  dt->DoDTMethodA(dtimg1, 0, 0, ARRAY(DTM_PROCLAYOUT, 0, 1));
               }
               if (dtimg2 != 0)
               {
                  dt->SetDTAttrsA(dtimg2, 0, 0, (TagItem*)ARRAY(
                     PDTA_Screen,         (iptr)_screen(obj), 
                     PDTA_DestMode,       PMODE_V43, 
                     PDTA_UseFriendBitMap,true,
                     TAG_DONE,            0));
                  
                  dt->DoDTMethodA(dtimg2, 0, 0, ARRAY(DTM_PROCLAYOUT, 0, 1));
               }
            }
         }
         break;

      case MUIM_AskMinMax:
         {
            DoSuperMtd(parent, obj, msg);

            minmax = (uint16*)msg[1];
            minmax[0] = width;
            minmax[2] = width;
            minmax[4] = width;
            minmax[1] = height;
            minmax[3] = height;
            minmax[5] = height;
         }
         return 0;

      case OM_SET:
         {
            bool flg;
            bool refresh = false;
//            image1 = (char*)GetTagData(MUIA_Picture_NormalImage,   (int32)image1.Data(), (TagItem*)msg[1]);
//            image2 = (char*)GetTagData(MUIA_Picture_SelectedImage, (int32)image2.Data(), (TagItem*)msg[1]);
            flg = Utility->GetTagData(MUIA_Disabled, isDisabled, (struct TagItem*)msg[1]) ? true : false;
            if (flg != isDisabled)
            {
               isDisabled = flg;
               refresh = true;
            }

            flg = Utility->GetTagData(MUIA_Selected, isSelected, (struct TagItem*)msg[1]) ? true : false;
            if (isSelected != flg)
            {
               isSelected = flg;
               refresh = true;
            }

            if (refresh)
               MUIMaster->MUI_Redraw(obj, 0);
         }
         break;

      case MUIM_NoNotifySet:
      case MUIM_Set:
         {
            bool refresh = false;
            if (msg[1] == MUIA_Picture_NormalImage)
               image1 = (char*)msg[2];

            if (msg[1] == MUIA_Picture_SelectedImage)
               image2 = (char*)msg[2];

            if (msg[1] == MUIA_Disabled)
            {
               bool flg = msg[2] ? true : false;
               if (flg != isDisabled)
               {
                  isDisabled = flg;
                  refresh = true;
               }
            }

            if (msg[1] == MUIA_Selected)
            {
               bool flg = msg[2] ? true : false;
               if (flg != isSelected)
               {
                  refresh = true;
                  isSelected = flg;
               }
            }
            if (refresh)
               MUIMaster->MUI_Redraw(obj, 0);
         }
         break;

      case MUIM_Draw:
         {
            Object* o = 0;
            BitMap* bitmap = 0;
            void*   drawinfo = 0;

            if (0 == _rp(obj)) 
               break;

            if ((isSelected) && (dtimg2 != 0))
               o = dtimg2;
            else if (dtimg1 != 0)
               o = dtimg1;
            else
               break;

            drawinfo = dt->ObtainDTDrawInfoA(o, (TagItem*)ARRAY(
               PDTA_Screen,   (iptr)_screen(obj),
               TAG_DONE,      0));

            if (drawinfo != 0)
            {
               dt->DrawDTObjectA(
                  _rp(obj),
                  o,
                  _mleft(obj),
                  _mtop(obj),
                  width,
                  height,
                  0,
                  0,
                  0);
               dt->ReleaseDTDrawInfo(o, drawinfo);
            }
            else
            {
               dt->GetDTAttrsA(o, (TagItem*)ARRAY(
                        PDTA_DestBitMap,     (iptr)&bitmap,
                        TAG_DONE,            0));
               if ((0 != bitmap) && (0 != GfxBase))
               {
#ifndef __amigaos4
                  BltBitMapRastPort(bitmap, 0, 0, _rp(obj), _mleft(obj), _mtop(obj), width, height, 0xc0);
#else
                  IGraphics->BltBitMapRastPort(bitmap, 0, 0, _rp(obj), _mleft(obj), _mtop(obj), width, height, 0xc0);
#endif
               }
            }
         }
         return 0;

   }
   return DoSuperMtd(parent, obj, msg);
}

void MUIPictureClass::openImages()
{
   if (dt == 0)
      return;

   closeImages();

   dtimg1 = dt->NewDTObjectA(image1.Data(), (TagItem*)ARRAY(
            DTA_GroupID,      (iptr)GID_PICTURE,
            PDTA_Remap,       true,
            OBP_Precision,    (iptr)PRECISION_EXACT,
            TAG_DONE,         0));

   dtimg2 = dt->NewDTObjectA(image2.Data(), (TagItem*)ARRAY(
            DTA_GroupID,      (iptr)GID_PICTURE,
            PDTA_Remap,       true,
            OBP_Precision,    (iptr)PRECISION_EXACT,
            TAG_DONE,         0));

   width  = 0x7fff;
   height = 0x7fff;

   if (dtimg1 != 0)
   {
      BitMapHeader *bmhd;

      dt->GetDTAttrsA(dtimg1, (TagItem*)ARRAY(
         PDTA_BitMapHeader,   (iptr)&bmhd,
         TAG_DONE,            0));

      width  = width  <? bmhd->bmh_Width;
      height = height <? bmhd->bmh_Height;
   }

   if (dtimg2 != 0)
   {
      BitMapHeader *bmhd;

      dt->GetDTAttrsA(dtimg1, (TagItem*)ARRAY(
         PDTA_BitMapHeader,   (iptr)&bmhd,
         TAG_DONE,            0));

      width  = width  <? bmhd->bmh_Width;
      height = height <? bmhd->bmh_Height;
   }

   if ((width == 0x7fff) && (height == 0x7fff))
   {
      width = 64;
      height = 48;
   }
}

void MUIPictureClass::closeImages()
{
   if (dt != 0)
   {
      if (dtimg1 != 0)
      {
         dt->DisposeDTObject(dtimg1);
      }
      if (dtimg2 != 0)
      {
         dt->DisposeDTObject(dtimg2);
      }
   }
   width    = 64;
   height   = 48;
   dtimg1   = 0;
   dtimg2   = 0;
}

iptr* MUIPictureClass::CreateClass()
{
    if (MUIPictureClass::muiclass == 0)
    {
	MUIPictureClass::muiclass = new MUICustomClassT<MUIPictureClass>(MUIC_Area);
    }
    return (iptr*)MUIPictureClass::muiclass;
}

void MUIPictureClass::DestroyClass()
{
    MUICustomClassT<MUIPictureClass> *p = MUIPictureClass::muiclass;
    MUIPictureClass::muiclass = 0;
    delete p;
}

查看irc.freenode.net上的#mui,并在此处报告错误/问题,以及MUI雅虎群组

华夏公益教科书