跳轉到內容

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雅虎群組

華夏公益教科書