ENGLISH VERSION |
|
Links | | | Forum | | | Kommentare | | | News melden |
Chat | | | Umfragen | | | Newsticker | | | Archiv |
amiga-news.de Forum > Programmierung > Gesucht: Sekundentakt | [ - Suche - Neue Beiträge - Registrieren - Login - ] |
1 -2- 3 4 | [ - Beitrag schreiben - ] |
20.06.2006, 12:57 Uhr Mad_Dog Posts: 1944 Nutzer |
Zitat: Er will damit sagen, daß Bäume auch umfallen, wenn keiner hinsieht - d.h. hier: Alle Ticks landen in der Message Queu, auch wenn das Programm "nicht hinschaut". -- http://www.norman-interactive.com [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 13:15 Uhr Holger Posts: 8116 Nutzer |
Zitat:Richtig, und sie sind vor allem auch dann da, wenn das Programm das nächste Mal hinschaut. Sprich, ob man vor jedem GetMsg ein WaitPort durchführt oder per erst GetMsg bis zum Erreichen von NULL iteriert, spielt keine Rolle, es sind trotzdem exakt die gleich Anzahl Messages in der Queue. Was anderes wäre es, wenn man per Wait wartet, dann könnten tatsächlich Signale verloren gehen, aber auch weiterhin keine Messages. Das heißt, wenn ein solches Programm z.B. auf den Closebutton wartet, kann es dann ziemlich lange dauern, bis es darauf reagiert, es muß aber trotzdem alle bis zum Klick auf den Button eingetroffenen Ticks bearbeiten. Die Frage, ob zwanzig ticks eintreffen, wenn man zwei Sekunden nach dem Programmstart auf den Closebutton klickt, läßt sich dann also genauso beantworten. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 13:20 Uhr Holger Posts: 8116 Nutzer |
Zitat:Klar. Man könnte ja z.B. immer die Titelzeile setzen, wenn das Fenster aktiv ist... Aber primär sollte man ticks dafür verwenden, wofür sie gedacht sind, für die Interaktion. Z.B. für autoscrolling oder kombinierte Eingabeaktionen, verzögertes feedback etc. Zitat: mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 13:21 Uhr whose Posts: 2156 Nutzer |
Zitat: Hm, auf die Ticks bezogen hat sich das Thema im Grunde ja schon erledigt. Es landet exakt einer in der Message Queue, bis er beantwortet wird. In Bezug auf die IntuiMessages stimmt das aber auch nur so lange, wie der Timeout der jeweilige Message nicht erreicht ist. Wenn mans ganz unklug anstellt, gehen da durchaus Ticks flöten (und andere Messages auch). Bei MOUSEMOVE-Events gibt es eine begrenzte Queue, da können auch Events flöten gehen, wenn man nicht schnell genug antwortet (ist mir oft genug passiert). Es hängt also vom Sender ab, ob die Messages bis in alle Ewigkeit "an der Kasse stehen". Bei Intuition ist es für die meisten Fälle wohl so, daß die "nach Hause gehen, wenn zu viele an der Kasse stehen und ihnen die Warterei auf die Nerven geht". Beim timer.device liegt der Fall etwas anders (bei Devices im Allgemeinen), denn da ist man selbst der Sender. Allerdings können einem auch da Events flöten gehen, wenn man schläft. Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 13:31 Uhr whose Posts: 2156 Nutzer |
Zitat: Wo ist der Sinn? Du meinst sicherlich, die Uhrzeit in der Titelzeile anzeigen... Zitat: Hmm, ich denke mal, für solche Anwendungsfälle fehlen schöne Beispiele. Hast Du da evtl. etwas auf Lager? Wenn das so weiter geht, wird Ralf mehr prima Spiele und Anwendungen in MaxonBasic basteln, Informationen kriegt er ja reichlich Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 13:37 Uhr Holger Posts: 8116 Nutzer |
Zitat:Das stimmt so eben nicht ganz. Es werden keine neuen mehr erzeugt, und die letzte in der queue reflektiert den aktuellen Status solange keine weiteren Events von einem anderen Typ erzeugt werden. Trotzdem bleiben die ersten Mouse-Events, die noch nicht wußten, daß es einen Engpaß geben wird, in der Queue. Kann man gut beobachten, wenn man in ein Malprogramm bei hoher Systemlast zeichnet. Die Abstände zwischen den registrierten Punkten werden immer größer, d.h. die ersten Events, die noch in einem sehr kleinen Abstand verschickt wurden, sind in der Queue geblieben, auch wenn der Zeitabstand für die nächsten Mouse-events zum Zeitpunkt des Abholens schon viel größer war. Zitat:Nee, sie stellen sich mitunter gar nicht erst an, wenn die Schlange zu lang ist. Aber wenn sie erstmal drin sind, bleiben sie auch da. Wäre auch viel zu aufwendig, ein vorzeitiges Verlassen bei Erhalt der Konsistenz zu implementieren. Das letzte MouseEvent in der Queue durch ein neueres ersetzen, oder einen Tick nicht verschicken, wenn noch einer in der Queue ist, das geht noch. Aber da hört es auch schon auf. Wie will man z.B. bei folgender Sequenz etwas entfernen, ohne die inhaltliche Aussage zu verändern? Move(x1,y1), Klick(x1,y1), Move(x2,y2), Diskinserted, KeyDown(shift), Klick(x2,y2), Move(x3,y3), KeyUp(shift), Klick(x3,y3) mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 13:41 Uhr Holger Posts: 8116 Nutzer |
Zitat:Oder den momentan verfügbaren Speicher, CPU-Last, CPU-Temperatur, Luftfeuchtigkeit... Zitat: Direkt auf Lager hab ich hier keine, aber so ein bißchen Zeit dafür da ist (sobald Deutschland ausgeschieden ist, duck und weg...), läßt sich vielleicht was machen. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 13:58 Uhr whose Posts: 2156 Nutzer |
Zitat: Ja, ich verstehe, was Du meintest. Und ich meinte etwas anderes, nämlich, daß Dir dadurch evtl. für Dich eigentlich wichtige Events verloren gehen. Ob sie gar nicht erst erzeugt werden oder ein Timeout haben, spielt da keine große Rolle, finde ich. Zitat:Zitat:Nee, sie stellen sich mitunter gar nicht erst an, wenn die Schlange zu lang ist. Aber wenn sie erstmal drin sind, bleiben sie auch da. Ich sagte ja auch "für die meisten Fälle". MOUSEMOVE-Events haben die eigene Queue mit begrenzter Länge, einige Events bleiben in der Message Queue erhalten. Ich kann mich aber ziemlich deutlich daran erinnern, daß es einige Intuition-Events mit Timeout gibt. Ich kann mich nur nicht so besonders konkret daran erinnern, welche das im einzelnen waren ("Libraries" immer noch nicht zur Hand, da unterwegs). IDCMP_SIZEVERIFY vielleicht? IDCMP_MENUVERIFY auf alle Fälle, das weiß ich aus leidvoller Erfahrung. Um den Rest habe ich mich noch nie besonders kümmern müssen, daher bin ich mir da alles andere als sicher. Ich sollte mich mal wieder intensiv mit Intuition beschäftigen, denke ich. Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 14:11 Uhr Holger Posts: 8116 Nutzer |
Zitat: Ach so, klar. Da gibt's spätestens seit 2.0 einen Timeout. Allerdings bin ich mir da gar nicht sicher, ob wirklich die Events aus der Queue entfernt werden. Bei dem Timeout geht es ja primär darum, daß das System nicht ewig auf die Anwendung wartet, und das Problem besteht ja z.B. auch, wenn die Message schon abgeholt wurde, aber nicht beanwortet wird. Deshalb hätte ich gedacht, daß in diesem Fall nur das System nicht mehr wartet und eine irgendwann doch noch eintretende Antwort ignoriert. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
20.06.2006, 14:16 Uhr whose Posts: 2156 Nutzer |
Zitat: Das weiß ich auch nicht so wahnsinnig genau... aber wäre wohl die logischste Vorgehensweise, einfach die Antworten zu ignorieren... und wieder was gelernt (und hoffentlich behalten ) Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
21.06.2006, 14:43 Uhr Mad_Dog Posts: 1944 Nutzer |
Hier kommt das leicht veränderte "Digitaluhr" Beispiel, diesmal unter Verwendung des timer.device:code:--/* * Eine einfache Digitaluhr * Diese Version verwendet das timer.device. * */ #include <stdio.h> #include <string.h> // Include-Datei für Strings #include <time.h> // Include-Datei für Zeit #include <exec/exec.h> #include <exec/types.h> #include <exec/io.h> #include <exec/memory.h> #include <devices/timer.h> #include <intuition/intuition.h> #include <graphics/gfx.h> #include <graphics/text.h> #include <proto/intuition.h> #include <proto/dos.h> #include <proto/exec.h> #include <proto/graphics.h> #include <proto/diskfont.h> // Funktionsprototypen der diskfont.library // Symbolische Konstanten #define WIDTH 130 // Breite des Fensters #define HEIGHT 70 // Höhe des Fensters struct Window *Fenster; // Zeiger auf Window-Struktur struct IntuitionBase *IntuitionBase; // Zeiger auf IntuitionBase-Struktur struct RastPort *rp; // Zeiger auf RastPort Struktur struct Library *DiskfontBase; // Zeiger auf DiskfontBase struct TextFont *textfont; // Zeiger auf TextFont struct TextAttr ta; // TextAttr Struktur struct timerequest *TimerIO; struct MsgPort *TimerMP; /* Funktionsprototypen */ void SchreibeZeit(struct RastPort *rp,int x,int y); void ShutDown(int code, STRPTR error); int main(void) { /* Variablen zur Message-Bearbeitung */ struct MsgPort *Port; // Zeiger auf Message Port Struktur struct IntuiMessage *Nachricht; // Zeiger auf Intuition Message Struktur ULONG klasse; USHORT code; ULONG Signale; int x,y; LONG black_pen,green_pen; // Variablen für Pens int x0,y0,x1,y1; BOOL Ende = FALSE; // Boolsche Variable: Programmende? // Intuition Library öffnen IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37L); if (IntuitionBase == NULL) ShutDown(10,"Konnte intuition.library 37 nicht öffnen."); // Disk Font Library öffnen DiskfontBase = OpenLibrary("diskfont.library",37L); if (DiskfontBase == NULL) ShutDown(10,"Konnte diskfont.library 37 nicht öffnen."); // Fenster mittels Tags öffnen Fenster = OpenWindowTags(NULL, WA_Left, 100, // Abstand vom linken Rand WA_Top, 100, // Abstand vom oberen Rand WA_Width, WIDTH, // Breite WA_Height, HEIGHT, // Höhe WA_Title, "Digitaluhr", // Fenstertitel WA_CloseGadget, TRUE, // Close-Gadget WA_DragBar, TRUE, // Ziehleiste WA_DepthGadget, TRUE, // Depth-Gadget WA_IDCMP, // IDCMP-Flags IDCMP_CLOSEWINDOW, WA_Activate, TRUE, // Fenster aktivieren TAG_DONE); if (Fenster == NULL) ShutDown(10,"Konnte Fenster nicht öffnen."); TimerMP = CreateMsgPort(); if (TimerMP == NULL) ShutDown(10,"Konnte Message Port nicht erzeugen."); TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest)); if (TimerIO == NULL) ShutDown(10,"Konnte Timerrequest nicht erzeugen."); OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerIO,0L); TimerIO->tr_node.io_Command = TR_GETSYSTIME; SendIO((struct IORequest *) TimerIO); rp = Fenster->RPort; /* TextAttr Struktur ausfüllen... */ ta.ta_Name = "helvetica.font"; // Name des Fonts ta.ta_YSize = 24; // Höhe des Fonts ta.ta_Style = FS_NORMAL; // Normaler Textstil ta.ta_Flags = FPF_DISKFONT; // Es ist ein Disk Font /* Die Funktion OpenDiskFont öffnet einen Font aus FONTS: */ textfont = (struct TextFont *) OpenDiskFont(&ta); if (textfont == NULL) ShutDown(10,"Konnte helvetica.font 24 nicht öffnen."); /* Pens ermitteln: Schwarz und Grün */ black_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap, 0x00000000,0x00000000,0x00000000, PRECISION_GUI, TAG_DONE); green_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap, 0x00000000,0xFFFFFFFF,0x00000000, PRECISION_GUI, TAG_DONE); /* In diesem Beispiel benutzen wir KEIN GimmeZeroZero Fenster. * Deshalb ermitteln die Maße der Zeichenfläche des Fensters * selbst... */ x0 = Fenster->BorderLeft; y0 = Fenster->BorderTop; x1 = Fenster->Width - Fenster->BorderRight-1; y1 = Fenster->Height - Fenster->BorderBottom-1; /* Jetzt übermalen wir die Zeichenfläche schwarz */ SetAPen(rp,black_pen); RectFill(rp,x0,y0,x1,y1); SetFont(rp,textfont); // Schriftart wählen SetAPen(rp,green_pen); // Pen für Vordergrund SetBPen(rp,black_pen); // Pen für Hintergrund /* Der Text soll zentriert dargestellt werden. * Deshalb errechnen wir, welchen Abstand der Text * vom linken Fensterrand haben muß. */ x = (x1-TextLength(rp,"00:00:00",8))/2; y = y0+30; SchreibeZeit(rp,x,y); Port = Fenster->UserPort; TimerIO->tr_node.io_Command = TR_ADDREQUEST; TimerIO->tr_time.tv_secs = 1; // Eine Nachricht pro Sekunde TimerIO->tr_time.tv_micro = 0; SendIO((struct IORequest *)TimerIO); /* Schleife läuft so lange, bis das Programm * durch Anklicken des Close-Gadgets beedet wird. */ while (!Ende) { /* Wir warten auf Signale von Intuition * oder vom timer.device. */ Signale = Wait((1UL << TimerMP->mp_SigBit) | (1UL << Port->mp_SigBit)); /* Die Uhr hat sich gemeldet... */ if(1UL << TimerMP->mp_SigBit) { WaitIO((struct IORequest *)TimerIO); TimerIO->tr_node.io_Command = TR_ADDREQUEST; TimerIO->tr_time.tv_secs = 1; // Eine Nachricht pro Sekunde TimerIO->tr_time.tv_micro = 0; SchreibeZeit(rp,x,y); SendIO((struct IORequest *)TimerIO); } /* Schleife läuft bis alle Ereignisse * abgearbeitet sind. */ while(Nachricht = (struct IntuiMessage *) GetMsg(Port)) { klasse = Nachricht->Class; code = Nachricht->Code; /* Welches Ereignis ist eingetreten? */ switch(klasse) { /* Close Gadget wurde angeklickt */ case CLOSEWINDOW : Ende = TRUE; // Programmende break; } // Ende der switch-Verzweigung /* Wir sind mit der Bearbeitung fertig * und beantworten die Nachricht. */ ReplyMsg((struct Message *)Nachricht); } // Ende der inneren while-Schleife } // Ende der äußeren while-Schleife AbortIO((struct IORequest *)TimerIO); WaitIO((struct IORequest *)TimerIO); CloseDevice((struct IORequest *) TimerIO); DeleteIORequest((struct IORequest *)TimerIO); DeleteMsgPort(TimerMP); // Die Pens wieder freigeben ReleasePen(Fenster->WScreen->ViewPort.ColorMap,black_pen); ReleasePen(Fenster->WScreen->ViewPort.ColorMap,green_pen); ShutDown(0,NULL); return 0; } /* SchreibeZeit * Schreibt die aktuelle Zeit an den Koordinaten x,y * in den RastPort rp. */ void SchreibeZeit(struct RastPort *rp,int x,int y) { struct tm *tp; // Zeiger auf tm Struktur time_t t; char Puffer[9]; // Puffer für 8 Zeichen + NULL time(&t); // Aktuelle Systemzeit holen tp = localtime(&t); // Zeitzonen berücksichtigen /* Aktuelle Zeit in Textpuffer schreiben... * Die Platzhalter des Format-Strings haben folgende Bedeutung: * * %H : Stunden * %M : Minuten * %S : Sekunden */ strftime(Puffer,sizeof(Puffer),"%H:%M:%S",tp); Move(rp,x,y); Text(rp,Puffer,8); } /* Resourcen freigeben */ void ShutDown(int code, STRPTR error) { if (textfont) CloseFont(textfont); if (DiskfontBase != NULL) CloseLibrary((struct Library *)DiskfontBase); if (Fenster != NULL) CloseWindow(Fenster); if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase); if (error) { printf("Fehler: %sn", error); } exit(code); } http://www.norman-interactive.com [ - Antworten - Zitieren - Direktlink - ] |
21.06.2006, 15:41 Uhr whose Posts: 2156 Nutzer |
@Mad_Dog: Auch ein schönes Beispiel,vielen Dank dafür Eins ist mir aber aufgefallen: Wozu schickst Du das Kommando TR_GETSYSTIME? Für die Auslösung des Timerevents ist es nicht nötig und time() aus der Standardbibliothek macht meines Wissens nach das Gleiche nochmal. Noch eine Kleinigkeit: Das simple AbortIO() sollte hier zwar keine Schwierigkeiten bereiten, "schöner" ist aber folgender Schnipsel: code:if(!(CheckIO())) { AbortIO(TimerIO); } WaitIO(TimerIO); CloseDevice((struct IORequest *)TimerIO); AbortIO() kann Schwierigkeiten bereiten, wenn man einen Request versucht abzubrechen, der gar nicht (mehr) gesendet wurde. CheckIO() gibt in diesem Fall einfach ein TRUE zurück und ein AbortIO() ist nicht mehr notwendig. Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
21.06.2006, 16:03 Uhr Mad_Dog Posts: 1944 Nutzer |
Zitat: Du hast natürlich Recht: In diesem Beispiel ist das doppelt gemoppelt. Das liegt daran, daß dies ein "mutierter Beispielcode" ist. Man könnte es auch so umbauen, daß die Zeit über das timer.device ermittelt wird. Eigentlich wollte ich nur ein Beispiel für Ralf bringen, das zeigt, wie man einen "zyklischen Alarm" setzen kann. -- http://www.norman-interactive.com [ - Antworten - Zitieren - Direktlink - ] |
21.06.2006, 16:05 Uhr whose Posts: 2156 Nutzer |
@Mad_Dog: Ah, ok Mit OS4 funktionierts übrigens auch ganz nett Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
21.06.2006, 16:20 Uhr thomas Posts: 7718 Nutzer |
@Mad_Dog:Zitat: Du solltest prüfen, ob das Device erfolgreich geöffnet wurde. Immerhin gibt es nicht unbegrenzt Timer im System. Zitat: Das muß OBP_Precision,PRECISION_GUI heißen ! So wie du es hier machst, hast du Glück, daß es nicht abstürzt, weil TAG_DONE fehlt (das TAG_DONE, das da steht wird als ti_Data von PRECISION_GUI genommen). Zitat: Wenn das fehlschlägt, wird TimerMP nicht freigegeben. Warum hast du die Device-Sachen nicht in der ShutDown-Prozedur berücksichtigt ? Gruß Thomas -- Email: thomas-rapp@web.de Home: thomas-rapp.homepage.t-online.de/ [ - Antworten - Zitieren - Direktlink - ] |
21.06.2006, 16:34 Uhr Mad_Dog Posts: 1944 Nutzer |
Zitat: Danke für die Hinweise. Den Code habe ich eben auf die Schnell mal zusammengebastelt und nicht an alles gedacht. -- http://www.norman-interactive.com [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 01:28 Uhr whose Posts: 2156 Nutzer |
Hier in der korrigierten und erweiterten Fassung:code:/* * Eine einfache Digitaluhr * Diese Version verwendet das timer.device. * (und geht, je nach Zeit zum Start, manchmal etwas nach */ #define INTUITION_PRE_V36_NAMES /* Wir verwenden iobsolete.h! Ältere Compiler ignorieren das */ #include <stdlib.h> #include <stdio.h> #include <exec/exec.h> #include <exec/types.h> #include <exec/io.h> #include <exec/memory.h> #include <devices/timer.h> #include <intuition/intuition.h> #include <graphics/gfx.h> #include <graphics/text.h> #include <proto/intuition.h> #include <proto/dos.h> #include <proto/exec.h> #include <proto/graphics.h> #include <proto/diskfont.h> // Funktionsprototypen der diskfont.library // Symbolische Konstanten #define WIDTH 130 // Breite des Fensters #define HEIGHT 70 // Höhe des Fensters struct Window *Fenster; // Zeiger auf Window-Struktur struct IntuitionBase *IntuitionBase; // Zeiger auf IntuitionBase-Struktur struct RastPort *rp; // Zeiger auf RastPort Struktur struct Library *DiskfontBase; // Zeiger auf DiskfontBase struct TextFont *textfont; // Zeiger auf TextFont struct TextAttr ta; // TextAttr Struktur struct timerequest *TimerIO; struct MsgPort *TimerMP; LONG timer; /* Funktionsprototypen */ void SchreibeZeit(struct RastPort *rp,int x,int y, ULONG sekunden, ULONG minuten, ULONG stunden); void ShutDown(int code, STRPTR error); int main(void) { /* Variablen zur Message-Bearbeitung */ struct MsgPort *Port; // Zeiger auf Message Port Struktur struct IntuiMessage *Nachricht; // Zeiger auf Intuition Message Struktur ULONG klasse; USHORT code; ULONG Signale; int x,y; LONG black_pen,green_pen; // Variablen für Pens int x0,y0,x1,y1; ULONG stunden, minuten, sekunden; BOOL Ende = FALSE; // Boolsche Variable: Programmende? // Intuition Library öffnen IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37L); if (IntuitionBase == NULL) ShutDown(10,"Konnte intuition.library 37 nicht öffnen."); // Disk Font Library öffnen DiskfontBase = OpenLibrary("diskfont.library",37L); if (DiskfontBase == NULL) ShutDown(10,"Konnte diskfont.library 37 nicht öffnen."); // Fenster mittels Tags öffnen Fenster = OpenWindowTags(NULL, WA_Left, 100, // Abstand vom linken Rand WA_Top, 100, // Abstand vom oberen Rand WA_Width, WIDTH, // Breite WA_Height, HEIGHT, // Höhe WA_Title, "Digitaluhr", // Fenstertitel WA_CloseGadget, TRUE, // Close-Gadget WA_DragBar, TRUE, // Ziehleiste WA_DepthGadget, TRUE, // Depth-Gadget WA_IDCMP, // IDCMP-Flags IDCMP_CLOSEWINDOW, WA_Activate, TRUE, // Fenster aktivieren TAG_DONE); if (Fenster == NULL) ShutDown(10,"Konnte Fenster nicht öffnen."); TimerMP = CreateMsgPort(); if (TimerMP == NULL) ShutDown(10,"Konnte Message Port nicht erzeugen."); TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest)); if (TimerIO == NULL) ShutDown(10,"Konnte Timerrequest nicht erzeugen."); timer = OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerIO,0L); if(timer != 0) ShutDown(10, "Konnte timer.device nicht öffnen."); rp = Fenster->RPort; /* TextAttr Struktur ausfüllen... */ ta.ta_Name = "helvetica.font"; // Name des Fonts ta.ta_YSize = 24; // Höhe des Fonts ta.ta_Style = FS_NORMAL; // Normaler Textstil ta.ta_Flags = FPF_DISKFONT; // Es ist ein Disk Font /* Die Funktion OpenDiskFont öffnet einen Font aus FONTS: */ textfont = (struct TextFont *) OpenDiskFont(&ta); if (textfont == NULL) ShutDown(10,"Konnte helvetica.font 24 nicht öffnen."); /* Pens ermitteln: Schwarz und Grün */ black_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap, 0x00000000,0x00000000,0x00000000, OBP_Precision, PRECISION_GUI, TAG_DONE); green_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap, 0x00000000,0xFFFFFFFF,0x00000000, OBP_Precision, PRECISION_GUI, TAG_DONE); /* In diesem Beispiel benutzen wir KEIN GimmeZeroZero Fenster. * Deshalb ermitteln die Maße der Zeichenfläche des Fensters * selbst... */ x0 = Fenster->BorderLeft; y0 = Fenster->BorderTop; x1 = Fenster->Width - Fenster->BorderRight-1; y1 = Fenster->Height - Fenster->BorderBottom-1; /* Jetzt übermalen wir die Zeichenfläche schwarz */ SetAPen(rp,black_pen); RectFill(rp,x0,y0,x1,y1); SetFont(rp,textfont); // Schriftart wählen SetAPen(rp,green_pen); // Pen für Vordergrund SetBPen(rp,black_pen); // Pen für Hintergrund /* Der Text soll zentriert dargestellt werden. * Deshalb errechnen wir, welchen Abstand der Text * vom linken Fensterrand haben muß. */ x = (x1-TextLength(rp,"00:00:00",8))/2; y = y0+30; /* Hier initialisieren wir dir Uhr einmal * "vorweg". Ansonsten wäre für eine * Sekunde nach dem Start nichts zu sehen */ TimerIO->tr_node.io_Command = TR_GETSYSTIME; /* DoIO(), weil der IORequest sonst (noch) keine Werte enthalten würde, * bis wir das Signal vom timer.device empfangen. Das ergäbe undefinierte * Inhalte der TimerIO-Struktur->Absturz */ DoIO((struct IORequest *) TimerIO); sekunden = (ULONG)TimerIO->tr_time.tv_secs; minuten = sekunden / 60; stunden = minuten / 60; sekunden = sekunden % 60; minuten = minuten % 60; stunden = stunden % 24; SchreibeZeit(rp,x,y, sekunden, minuten, stunden); Port = Fenster->UserPort; TimerIO->tr_node.io_Command = TR_ADDREQUEST; TimerIO->tr_time.tv_secs = 1; // Eine Nachricht pro Sekunde TimerIO->tr_time.tv_micro = 0; SendIO((struct IORequest *)TimerIO); /* Schleife läuft so lange, bis das Programm * durch Anklicken des Close-Gadgets beedet wird. */ while (!Ende) { /* Wir warten auf Signale von Intuition * oder vom timer.device. */ Signale = Wait((1UL << TimerMP->mp_SigBit) | (1UL << Port->mp_SigBit)); /* Die Uhr hat sich gemeldet... */ if(Signale & (1UL << TimerMP->mp_SigBit)) { WaitIO(); /* MessagePort von der Antwort des timer.device "befreien". * WaitIO() "wartet" hier nicht wirklich, sondern kehrt sofort * zurück. Hier nehmen wir es, weil WaitIO() freundlicherweise * auch noch den MessagePort "aufräumt". Man könnte das auch * selbst per GetMsg(TimerMP) erldigen. TimerIO->tr_node.io_Command = TR_GETSYSTIME; DoIO((struct IORequest *) TimerIO); sekunden = (ULONG)TimerIO->tr_time.tv_secs; minuten = sekunden / 60; stunden = minuten / 60; sekunden = sekunden % 60; minuten = minuten % 60; stunden = stunden % 24; TimerIO->tr_node.io_Command = TR_ADDREQUEST; TimerIO->tr_time.tv_secs = 1; // Eine Nachricht pro Sekunde TimerIO->tr_time.tv_micro = 0; SendIO((struct IORequest *)TimerIO); SchreibeZeit(rp,x,y, sekunden, minuten, stunden); } /* Schleife läuft bis alle Ereignisse * abgearbeitet sind. */ while(Nachricht = (struct IntuiMessage *) GetMsg(Port)) { klasse = Nachricht->Class; code = Nachricht->Code; /* Welches Ereignis ist eingetreten? */ switch(klasse) { /* Close Gadget wurde angeklickt */ case CLOSEWINDOW : Ende = TRUE; // Programmende break; } // Ende der switch-Verzweigung /* Wir sind mit der Bearbeitung fertig * und beantworten die Nachricht. */ ReplyMsg((struct Message *)Nachricht); } // Ende der inneren while-Schleife } // Ende der äußeren while-Schleife if(!(CheckIO((struct IORequest *)TimerIO))) { AbortIO((struct IORequest *)TimerIO); } WaitIO((struct IORequest *)TimerIO); CloseDevice((struct IORequest *) TimerIO); timer = 1; // wir kommen ja noch zu ShutDown()... DeleteIORequest((APTR)TimerIO); TimerIO = NULL; // ...zwei Mal freigeben ist nie eine gute Idee DeleteMsgPort(TimerMP); TimerMP = NULL; // Die Pens wieder freigeben ReleasePen(Fenster->WScreen->ViewPort.ColorMap,black_pen); ReleasePen(Fenster->WScreen->ViewPort.ColorMap,green_pen); ShutDown(0,NULL); return 0; } /* SchreibeZeit * Schreibt die aktuelle Zeit an den Koordinaten x,y * in den RastPort rp. */ void SchreibeZeit(struct RastPort *rp,int x,int y, ULONG sekunden, ULONG minuten, ULONG stunden) { char Puffer[9]; // Puffer für 8 Zeichen + NULL /* kopieren der Zeitwerte in den Puffer, * jeder Wert hat mindestens zwei Ziffern * mit ggf. führender 0 */ sprintf(Puffer, "%02d:%02d:%02d", stunden, minuten, sekunden); Move(rp,x,y); Text(rp,Puffer,8); } /* Resourcen freigeben */ void ShutDown(int code, STRPTR error) { // OpenDevice() gibt 0 zurück, falls Erfolg! if(!timer) CloseDevice((struct IORequest *)TimerIO); if(TimerIO) DeleteIORequest((APTR)TimerIO); if(TimerMP) DeletePort(TimerMP); if (textfont) CloseFont(textfont); if (DiskfontBase != NULL) CloseLibrary((struct Library *)DiskfontBase); if (Fenster != NULL) CloseWindow(Fenster); if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase); if (error) { printf("Fehler: %sn", error); } exit(code); } Edit: Dussligen Fehler bei "if(Signale & (1UL << TimerMP->mp_SigBit))" (das "==") beseitigt, WaitIO() eingefügt (danke an thomas). -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ Dieser Beitrag wurde von whose am 22.06.2006 um 01:39 Uhr geändert. ] [ Dieser Beitrag wurde von whose am 22.06.2006 um 03:16 Uhr geändert. ] [ Dieser Beitrag wurde von whose am 26.06.2006 um 16:22 Uhr geändert. ] [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 01:52 Uhr whose Posts: 2156 Nutzer |
Argh, ich seh grad, ich hätte in der Wait()-Schleife TR_ADDREQUEST vor TR_GETSYSTIME setzen sollen... naja, wers ausprobieren möchte, kann die Stelle ja umsortieren. Hinweis für OS4-Nutzer (und OS4-C-Anfänger): Linken mit libauto.a und libamiga.a, zusätzlich #define __USE_INLINE__ setzen (wegen der geänderten Konventionen für Funktionsaufrufe ala "IFace->blablabla()", mit dem #define wird die herkömmliche Art benutzt) und die OpenLibrary()/CloseLibrary()-Geschichten auskommentieren/entfernen. Selbiges gilt für die Deklarationen der Library-Strukturen (IntuitionBase und DiskFontBase), auskommentieren/entfernen. -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 11:47 Uhr Reth Posts: 1858 Nutzer |
Mal ne dumme Frage: Muss man das ReplyMsg nach Abarbeitung der Message oder davor rufen, oder ist das egal? [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 13:03 Uhr Ralf27 Posts: 2779 Nutzer |
Zitat: Hm, aus der reinen überlegung herraus würde ich tippen das man erst ReplyMsg aufrufen darf, wenn die Message bearbeitet wurde, bzw. erst aufrufen wenn alle Daten aus der Struktur gelesen worden sind. Denn wenn noch mehr Messages warten, dann wird die aktuelle Message nach dem sofortigen Aufruf von ReplyMsg ja durch die neue überschrieben, die ja schon sozusagen hinten dran stehen könnte. Also erst ReplyMsg, wenn alle Daten aus der Struktur gelesen worden sind, bzw. alles verarbeitet worden ist. -- http://www.alternativercomputerclub.de.vu [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 13:26 Uhr Holger Posts: 8116 Nutzer |
Zitat: Aus Sicht einer resourcenschonenden Strategie sollte man sie so schnell wie möglich beantworten, damit der Speicher wiederverwendet werden kann. Wie hier aber schon gesagt wurde, muß man alle Daten, die man benötigt, vorher rauskopieren. Nach der Beantwortung (wird ja auch gerne als Zurückschicken bezeichnet), darf man nicht mehr auf die Nachricht zugreifen. Und bei Nachrichten, die eine Antwort beinhalten, sollte man natürlich auch erst antworten, wenn man die Antwort kennt. Das gilt für die ...VERIFY Messages und natürlich auch für die TICKS, deren Beantwortung ja impliziert, daß jetzt ein neuer Tick gesendet werden darf. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 14:36 Uhr whose Posts: 2156 Nutzer |
Zitat: Wie meinst Du das? Meinst Du mit Antwort eine Nachricht, die als Reply auf eine eigene Nachricht eintrifft? Die braucht man nicht wieder zu beantworten, da man selbst "Besitzer" des Speichers der Nachricht ist. Das ist z.B. bei den Nachrichten eines Devices als Antwort auf einen IORequest der Fall. Solltest Du das anders meinen, wäre ne kleine Erläuterung nicht schlecht. Irgendwie ist der Satz mit den Antworten etwas verwirrend Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 17:39 Uhr Holger Posts: 8116 Nutzer |
@whose: Wenn Du z.B. eine MENUVERIFY Message beantwortest, teilst Du mit, ob Du mit dem Öffnen des Menüs einverstanden bist, oder nicht. Du kannst also die Message erst beantworten, wenn Du weißt ob Du mit Ok oder Cancel antworten willst. Das meinte ich mit, Du mußt Deine Antwort erst mal kennen. Wenn diese Antwort das Ergebnis Deiner Verarbeitung ist, kannst Du natürlich die Message nicht vorher beantworten. Das ist eben etwas anderes, als die Verarbeitung eines Tastendrucks. Da kannst Du das Zeichen kopieren, Message zurückschicken, Dokument aktualisieren, Dokument neu zeichnen, nächste Nachricht bearbeiten... mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 18:59 Uhr whose Posts: 2156 Nutzer |
Zitat: Ah, ok, so war das gemeint. Ja, in den Fällen ist das klar. Der Satz hatte mich halt etwas verwirrt Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
22.06.2006, 21:56 Uhr whose Posts: 2156 Nutzer |
Uiuiui, ich seh grad noch nen Patzer (der war schon in der ersten Fassung drin, total übersehen):code:/* Die Uhr hat sich gemeldet... */ if(1UL << TimerMP->mp_SigBit) das müßte code:if(Signale == (1UL << TimerMP->mp_SigBit)) lauten. In der ursprünglichen Fassung ist es mehr oder weniger Zufall, daß es funktioniert, wie gedacht. Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
26.06.2006, 11:23 Uhr Mad_Dog Posts: 1944 Nutzer |
Zitat: Warum denn das? Wenn TimerMP->mp_SigBit wahr ist, dann mach ich die folgende Anweisung, ansonsten nicht. Die Variable "Signale" ist in dem Code fehl am Platz... sorry -- http://www.norman-interactive.com [ Dieser Beitrag wurde von Mad_Dog am 26.06.2006 um 11:26 Uhr geändert. ] [ - Antworten - Zitieren - Direktlink - ] |
26.06.2006, 11:33 Uhr thomas Posts: 7718 Nutzer |
Zitat: 1UL << TimerMP->mp_SigBit ist immer wahr. Normalerweise macht man das so: code:sigflag1 = 1 << port1->mp_SigBit; sigflag2 = 1 << port2->mp_SigBit; sigflag3 = 1 << port3->mp_SigBit; signals_received = Wait (sigflag1 | sigflag2 | sigflag3); if (signals_received & sigflag1) { while (msg1 = GetMsg (port1)) { /* message(s) an port1 verarbeiten */ ReplyMsg (msg1); } } if (signals_received & sigflag2) { while (msg2 = GetMsg (port2)) { /* message(s) an port2 verarbeiten */ ReplyMsg (msg2); } } if (signals_received & sigflag3) { while (msg3 = GetMsg (port3)) { /* message(s) an port3 verarbeiten */ ReplyMsg (msg3); } } Die Abfrage mit == ist genauso falsch wie ganz ohne Signale. Gruß Thomas -- Email: thomas-rapp@web.de Home: thomas-rapp.homepage.t-online.de/ [ Dieser Beitrag wurde von thomas am 26.06.2006 um 11:42 Uhr geändert. ] [ - Antworten - Zitieren - Direktlink - ] |
26.06.2006, 11:45 Uhr thomas Posts: 7718 Nutzer |
Ich sehe gerade, in eurem Code ist noch ein Fehler drin: nach dem Aufruf von SendIO muß unbedingt WaitIO aufgerufen werden, bevor der IORequest wieder verwendet werden darf. Korrekt muß es also so lauten: code:/* Die Uhr hat sich gemeldet... */ if(Signale & (1UL << TimerMP->mp_SigBit)) { WaitIO ((struct IORequest *) TimerIO); TimerIO->tr_node.io_Command = TR_GETSYSTIME; DoIO((struct IORequest *) TimerIO); Gruß Thomas -- Email: thomas-rapp@web.de Home: thomas-rapp.homepage.t-online.de/ [ - Antworten - Zitieren - Direktlink - ] |
26.06.2006, 13:45 Uhr whose Posts: 2156 Nutzer |
Zitat: Ja, mit "==" war Bockmist, Weiß auch nicht, wie ich da drauf gekommen bin, hier bei mir stehts richtig im Programm Zum WaitIO(): Aus welchem Grund muß denn, wenn das timer.device das Signal gesetzt hat, nochmal extra auf Beendigung des Requests gewartet werden? Darf man nicht davon ausgehen, daß der Request bearbeitet wurde, wenn das gewünschte Signal eintrifft? Ich frage so dusslig, weil ich zum WaitIO() an dieser Stelle weder in den RKMs noch in den AutoDocs was finde... Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Antworten - Zitieren - Direktlink - ] |
26.06.2006, 13:47 Uhr gni Posts: 1106 Nutzer |
Zitat:Und ohne Casts wäre es noch viel besser... [ - Antworten - Zitieren - Direktlink - ] |
1 -2- 3 4 | [ - Beitrag schreiben - ] |
amiga-news.de Forum > Programmierung > Gesucht: Sekundentakt | [ - Suche - Neue Beiträge - Registrieren - Login - ] |
Impressum |
Datenschutzerklärung |
Netiquette |
Werbung |
Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten. |