Erstellen einer Fensteranwendung in reinem C unter MacOS
Lesezeit: 11 Minuten
Mago
Ich erstelle eine Anwendung in reinem C unter Mac OSX. Ich möchte ein Fenster erstellen, in dem meine App angezeigt wird.
Am liebsten möchte ich, dass es sich um eine reine C-Lösung handelt, aber wenn ich die Objective-C-Klasse verwenden muss, um das Fenster zu initialisieren und dann einen Kontext an meinen C-Code zu senden, ist das in Ordnung.
Ich verwende kein Xcode, sondern nur einen einfachen Texteditor. Ich habe versucht, Cocoa zu importieren, aber es wurden nur viele Fehler generiert.
Wie schreibe ich Code in einfachem reinem C-Code, der ein Fenster in OSX anzeigt?
Xcode ist keine Voraussetzung zum Schreiben einer Cocoa-App für OS X, aber es verringert die Schwierigkeit wesentlich. Sofern Sie nicht vorhaben, eine X-Window-Anwendung zu schreiben und sich beim Rendern auf Quartz oder einen anderen Fenstermanager zu verlassen, wird Pure-C so gut wie nicht passieren. Minimalistischer Kakao mit Objective-C dann ist es machbar, Ihre Kernlogik in C zu vergraben, aber am Ende fällt es Ihnen vielleicht leichter, am Ende einfach nur Objective-C zu verwenden.
– WhozCraig
15. Mai 2015 um 22:04
Was möchten Sie im Fenster anzeigen? Statischer Text, bearbeitbarer Text, UI-Steuerelemente, 3D-Grafiken …?
– JWWalker
15. Mai 2015 um 23:31 Uhr
@JWWalker-Leinwand, auf der ich zeichnen werde
– Mago
15. Mai 2015 um 23:36
Wenn Sie bereit sind, Ihre Zeichnungen mit OpenGL zu erstellen, können Sie das GLUT-Framework verwenden. Sehen glutInit, glutCreateWindow usw.
– JWWalker
16. Mai 2015 um 0:21
@Mago Diese Frage ist ein Duplikat der anderen Frage, da sie dasselbe fragt – wie man eine Cocoa-App in C schreibt. Die zugrunde liegende Technik für iOS und OS X ist dieselbe – verwenden Sie die Laufzeit-API. In dieser Frage gibt es sogar ein OS X-Beispiel. Diese Frage ist also ein Duplikat.
– SevenBits
16. Mai 2015 um 12:33
hasen
Ich habe eine Übersetzung der akzeptierten Antwort auf Pure C gemacht:
Dadurch wird die Cocoa-App mit einem Fenster ausgeführt. Wie auf dem Screenshot unten
Sie können ein Menü tatsächlich mit NSMenu hinzufügen
id applicationMenuBar = [NSMenu new];
id appMenuItem = [NSMenuItem new];
[applicationMenuBar addItem:appMenuItem];
[NSApp setMainMenu: applicationMenuBar];
Diese Antwort ist falsch. Sie müssen Objective-C nicht für die Benutzeroberfläche verwenden. Sie können die meisten Objective-C-Klassen von C aus mithilfe der Objective-C-Laufzeit-API aufrufen und die UI-Elemente programmgesteuert erstellen. Es ist nicht praktikabel, aber es ist machbar.
– SevenBits
15. Mai 2015 um 22:22
Könnten Sie bitte ein Beispiel geben?
– Weinendes Nilpferd
15. Mai 2015 um 22:24
Das gilt für iOS, gilt aber gleichermaßen auch für OS X.
– SevenBits
15. Mai 2015 um 22:25
Bei diesem Beispielcode handelt es sich nicht um eine „Mischung von C/C++ und Objective-C“, sondern vielmehr rein Ziel c.
– niemand
15. Mai 2015 um 22:49
Diese Antwort hätte nicht akzeptiert werden dürfen. Es ist nicht die richtige Antwort auf die Frage – dieses Programm ist reines Objective-C, und der OP gab an, dass er das Programm in reinem C (dh ohne Objective-C) schreiben wollte.
– SevenBits
16. Mai 2015 um 12:30 Uhr
Kannst du das tun? Ja und nein (das können Sie tun). irgendetwas wenn Sie hartnäckig genug sind). ja du dürfenaber nein du sollte nicht. Unabhängig davon kann dies für die unglaublich Hartnäckigen unter Ihnen getan werden. Da das Codieren eines Beispiels eine Weile dauern wird, habe ich im Internet eine großzügige Seele gefunden, die es bereits getan hat. Suchen in diesem Repository auf GitHub für den vollständigen Code und Erklärungen. Hier einige Ausschnitte:
cmacs_simple_msgSend((id)objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
if (NSApp == NULL) {
fprintf(stderr,"Failed to initialized NSApplication... terminating...\n");
return;
}
id appDelObj = cmacs_simple_msgSend((id)objc_getClass("AppDelegate"), sel_getUid("alloc"));
appDelObj = cmacs_simple_msgSend(appDelObj, sel_getUid("init"));
cmacs_void_msgSend1(NSApp, sel_getUid("setDelegate:"), appDelObj);
cmacs_void_msgSend(NSApp, sel_getUid("run"));
Wie Sie feststellen werden, verwendet dieser Code die Objective-C-Laufzeit-API, um ein falsches AppDelegate zu erstellen. Und das Erstellen des Fensters ist ein komplizierter Prozess:
self->window = cmacs_simple_msgSend((id)objc_getClass("NSWindow"), sel_getUid("alloc"));
/// Create an instance of the window.
self->window = cmacs_window_init_msgSend(self->window, sel_getUid("initWithContentRect:styleMask:backing:defer:"), (CMRect){0,0,1024,460}, (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask), 0, false);
/// Create an instance of our view class.
///
/// Relies on the view having declared a constructor that allocates a class pair for it.
id view = cmacs_rect_msgSend1(cmacs_simple_msgSend((id)objc_getClass("View"), sel_getUid("alloc")), sel_getUid("initWithFrame:"), (CMRect){ 0, 0, 320, 480 });
// here we simply add the view to the window.
cmacs_void_msgSend1(self->window, sel_getUid("setContentView:"), view);
cmacs_simple_msgSend(self->window, sel_getUid("becomeFirstResponder"));
// Shows our window in the bottom-left hand corner of the screen.
cmacs_void_msgSend1(self->window, sel_getUid("makeKeyAndOrderFront:"), self);
return YES;
Also ja. Sie können eine Cocoa-App in reinem C schreiben. Aber ich würde es nicht empfehlen. 90 % dieses Codes können durch eine xib-Datei ersetzt werden, und wenn Sie dies tun, wird Ihre App wirklich eingeschränkt, da erweiterte Funktionen des Apple-Entwicklungsstapels wirklich auf Objective-C-Funktionen basieren. Obwohl es technisch möglich ist, alles auf diese Weise zu machen, machen Sie es viel schwieriger, als es sein sollte.
Tyler Curtis Jowers
Ich erinnere mich, dass ich diese Frage vor etwa einem Jahr gesehen habe, damals, als ich mir so verzweifelt wünschte, ich könnte das Werbefenster öffnen, tagelang gegoogelt und nur die Art von Antworten gefunden habe, die Sie über diesem Beitrag sehen.
Ich habe mich über das Betriebssystem informiert, auf dem der Mac basiert – Berkley Software Distribution. http://codex.cs.yale.edu/avi/os-book/OS9/appendices-dir/a.pdf Wo mir auf Seite 17 der Satz „…X Windowing System entwickelt am MIT“ ins Auge fiel und ich mich daran erinnerte, wie ich ein Fenster nicht öffnen konnte und wie sauer ich darüber war, und ich dachte, das wäre vielleicht endlich die Lösung!
Ich habe nach „BSD X Window Programming“ gegoogelt und bin zufällig dazu gelangt, endlich ein Fenster in reinem C zu öffnen.
Ich habe es gerade erst entdeckt, also bin ich noch kein Meister, aber schauen Sie sich diesen Link an https://en.wikibooks.org/wiki/X_Window_Programming/Xlib und gehen Sie zum Beispiel. Befolgen Sie unbedingt die Kommentare oben zum Kompilieren mit der X11-Bibliothek (Sie können die Befehle -Wall und -O ignorieren, solange Sie über -lX11 verfügen).
Wenn Sie nicht kompilieren können oder die Header-Dateien nicht finden können, müssen Sie ihm beim Auffinden der Header-Dateien helfen.
Es kann sein, dass sich die X11-Inhalte an verschiedenen Stellen auf Ihrem System befinden. Höchstwahrscheinlich werden Sie es finden /opt/X11/include Hier finden Sie alle Definitionen der benötigten Header.
Sie könnten den vollständigen Pfad in Ihre C-Programme einbinden, z. B.:
#include "/opt/X11/include/X11/Xlib.h"
Aber wir wollen, dass es so aussieht #include <X11/Xlib.h>
Sie können diesen Schalter also beim Kompilieren zu GCC hinzufügen -I /opt/X11/include
Oder gehen Sie zu Ihrem .profile oder .bashrc oder .bash_profile in Ihrem Home-Verzeichnis und fügen Sie hinzu:
Einfache Xlib-Anwendung, die ein Feld in einem Fenster zeichnet.
*/
Aus dem Wiki:
#include<X11/Xlib.h>
#include<stdio.h>
#include<stdlib.h> // prevents error for exit on line 18 when compiling with gcc
int main() {
Display *d;
int s;
Window w;
XEvent e;
/* open connection with the server */
d=XOpenDisplay(NULL);
if(d==NULL) {
printf("Cannot open display\n");
exit(1);
}
s=DefaultScreen(d);
/* create window */
w=XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
BlackPixel(d, s), WhitePixel(d, s));
// Process Window Close Event through event handler so XNextEvent does Not fail
Atom delWindow = XInternAtom( d, "WM_DELETE_WINDOW", 0 );
XSetWMProtocols(d , w, &delWindow, 1);
/* select kind of events we are interested in */
XSelectInput(d, w, ExposureMask | KeyPressMask);
/* map (show) the window */
XMapWindow(d, w);
/* event loop */
while(1) {
XNextEvent(d, &e);
/* draw or redraw the window */
if(e.type==Expose) {
XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
}
/* exit on key press */
if(e.type==KeyPress)
break;
// Handle Windows Close Event
if(e.type==ClientMessage)
break;
}
/* destroy our window */
XDestroyWindow(d, w);
/* close connection to server */
XCloseDisplay(d);
return 0;
}
Kompilieren:
gcc -O2 -Wall -o test test.c -L /usr/X11R6/lib -lX11 -lm
miauen
Leider funktioniert die am besten bewertete Antwort aufgrund einer ABI-Nichtübereinstimmung nicht auf neuen Apple Silicon-Geräten. Grundsätzlich können Sie auf ARM64 die objc_msgSend-Deklaration nicht mit variablen Argumenten verwenden, Sie müssen für jeden Aufruf die richtigen Argumenttypen angeben. Hier ist die Version, die auf Apple Silicon läuft:
Ich erstelle eine Anwendung in reinem C unter Mac OSX. Ich möchte ein Fenster erstellen, in dem meine App gespeichert wird.
Suchen Sie ein TTY-Fenster?
Wenn ja, muss Ihre Anwendung das Fenster erstellen?
Wenn nicht, können Sie einfach Ihr reines C-Programm schreiben und es im Terminal ausführen – einer TTY-Umgebung für „reines C“.
Wenn Sie eine doppelklickbare App wünschen, können Sie ein AppleScript schreiben, das Terminal öffnet und Ihr C ausführt. Etwas wie:
tell application "Terminal"
do script "ex /tmp/test; exit"
end tell
Dadurch wird ein Terminalfenster geöffnet, in dem „ex“ angezeigt wird. Wenn dieses Fenster geschlossen wird, wird der Shell-Prozess beendet (es können also keine weiteren Befehle eingegeben werden). Dies geschieht jedoch nicht Schließen Sie das Terminal selbst – dafür müssen Sie sich mehr anstrengen.
Wenn Sie möchten, dass Ihre Anwendung das Fenster selbst erstellt, müssen Sie entweder Ihr eigenes einfaches TTY-Fenster schreiben, möglicherweise finden Sie einige Klassen, die Sie verwenden können, oder Sie können Code von einer Open-Source-Terminal-App ausleihen, z iterm.
HTH
Er machte deutlich, dass er möchte, dass C-Code ein OS X-Fenster (dh Cocoa) generiert. Daher glaube ich nicht, dass die Verwendung einer terminalbasierten App für seine Bedürfnisse angemessen wäre.
– SevenBits
16. Mai 2015 um 12:36 Uhr
@SevenBits – Da ich die Antwort geschrieben habe, sucht der OP tatsächlich nach einer „Leinwand, auf der ich zeichnen werde“; Wenn es sich also nicht um VT100-Grafiken handelt, was ich bezweifle, ist diese Antwort nicht geeignet, wie Sie richtig beobachten. Zukünftige Leser möchten jedoch möglicherweise „TTY-Code“ in einem Fenster unter OS X ausführen, daher habe ich die Antwort hinterlassen.
– CRD
16. Mai 2015 um 17:05 Uhr
14541000cookie-checkErstellen einer Fensteranwendung in reinem C unter MacOSyes
Xcode ist keine Voraussetzung zum Schreiben einer Cocoa-App für OS X, aber es verringert die Schwierigkeit wesentlich. Sofern Sie nicht vorhaben, eine X-Window-Anwendung zu schreiben und sich beim Rendern auf Quartz oder einen anderen Fenstermanager zu verlassen, wird Pure-C so gut wie nicht passieren. Minimalistischer Kakao mit Objective-C dann ist es machbar, Ihre Kernlogik in C zu vergraben, aber am Ende fällt es Ihnen vielleicht leichter, am Ende einfach nur Objective-C zu verwenden.
– WhozCraig
15. Mai 2015 um 22:04
Was möchten Sie im Fenster anzeigen? Statischer Text, bearbeitbarer Text, UI-Steuerelemente, 3D-Grafiken …?
– JWWalker
15. Mai 2015 um 23:31 Uhr
@JWWalker-Leinwand, auf der ich zeichnen werde
– Mago
15. Mai 2015 um 23:36
Wenn Sie bereit sind, Ihre Zeichnungen mit OpenGL zu erstellen, können Sie das GLUT-Framework verwenden. Sehen
glutInit
,glutCreateWindow
usw.– JWWalker
16. Mai 2015 um 0:21
@Mago Diese Frage ist ein Duplikat der anderen Frage, da sie dasselbe fragt – wie man eine Cocoa-App in C schreibt. Die zugrunde liegende Technik für iOS und OS X ist dieselbe – verwenden Sie die Laufzeit-API. In dieser Frage gibt es sogar ein OS X-Beispiel. Diese Frage ist also ein Duplikat.
– SevenBits
16. Mai 2015 um 12:33