Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 14 Xlib – X Window-Programmierung
  gp 14.1 Architektur von X
    gp 14.1.1 Pufferung
    gp 14.1.2 Ressourcen
  gp 14.2 X Toolkit
  gp 14.3 Der Window-Manager
  gp 14.4 Fenster mit X
    gp 14.4.1 Verbindung herstellen
    gp 14.4.2 Fenster definieren
    gp 14.4.3 Informationen für den Window-Manager
    gp 14.4.4 Fenster anzeigen
    gp 14.4.5 Fenster und X-Verbindung beenden
    gp 14.4.6 Das Grundgerüst als Quellcode
  gp 14.5 Events
    gp 14.5.1 Event-Maske setzen
    gp 14.5.2 Event-Bearbeitungsschleife
    gp 14.5.3 Abarbeitung der Events
    gp 14.5.4 Tastatur-Event
    gp 14.5.5 Mausbutton-Event
    gp 14.5.6 Expose-Event
    gp 14.5.7 EnterWindowMask – LeaveWindowMask
    gp 14.5.8 Listing zu den Events
  gp 14.6 Grafik mit X
    gp 14.6.1 Grafikprimitive – Zeichenfunktionen
  gp 14.7 Text mit X
    gp 14.7.1 Fonts benutzen
    gp 14.7.2 Übersicht zu den Fonts
    gp 14.7.3 Höhe und Breite ermitteln
    gp 14.7.4 Listing mit Textausgabe
  gp 14.8 Farben mit X
  gp 14.9 Beispiel – ein Button mit X
  gp 14.10 Wozu kann ich denn nun die Xlib in der Praxis verwenden?
  gp 14.11 X und X-Toolkits – Einführung
  gp 14.12 Toolkit-Programmierung
    gp 14.12.1 Widgets
  gp 14.13 Ein einfaches Fenster mit einem Button
    gp 14.13.1 Ressourcen
  gp 14.14 Zwei Buttons in Box- und Form-Widget mit Textausgabe (Label-Widget)
  gp 14.15 editres – Widget-Hierarchie
  gp 14.16 Texteingabe mit Dialog-Widget
  gp 14.17 X-Toolkits meets Xlib
  gp 14.18 Zusammenfassung


Rheinwerk Computing

14.7 Text mitdowntop

Unter X haben Sie die Möglichkeit, aus einer unzähligen Menge von Schriften zu wählen. Standardmäßig wird immer der ASCII-Zeichensatz unterstützt (Zeichen Nr. 20 bis 126) – aber häufig finden dabei auch die ausländischen Schriftzeichen zwischen 128 und 255 Platz. Für jede Schriftgröße wird ein eigener Font benötigt, was dazu führt, dass eine enorme Menge an Fonts vorhanden ist (auf meinem Rechner sind dies ca. 3200). Jeder Font, der gerade verwendet wird, besitzt eine eigene Kennungs-ID, die im Grafikkontext gespeichert wird. Somit benötigen Sie auch für die Ausgabe von Schriften den Grafikkontext GC.


Rheinwerk Computing

14.7.1 Fonts benutzen  downtop

Standardmäßig verwendet der Grafikkontext eine voreingestellte Schriftart. Sofern Sie eine andere Schriftart verwenden wollen, müssen Sie diese erst laden. Folgende Schritte sind dazu nötig:

1. Font mit der Funktion XLoadFont() laden:
       
Display *display; Font font; ... font = XLoadFont (display, fontname);
    Als Rückgabewert erhalten Sie eine Kennungs-ID font vom Typ Font, die Sie für weitere Funktionsaufrufe benötigen werden. fontname ist ein String mit einer bestimmten Schriftart. Hierbei ist auch z. B. "*normal--10*" erlaubt – dann sucht sich der Server einfach irgendeine Schriftart normaler Dicke mit 10 Pixel Höhe aus.
       
2. Font (Schriftart) im Grafikkontext GC eintragen (Font setzen):
       
Display *display;  GC mygc; Font font; ... XSetFont (display, mygc, font);
3. Text mit der Funktion XDrawString() oder XDrawImageString() ausgeben:
       
Display *display;  Window win;  GC mygc; int x, y, len; char *text; ... XDrawString (display, win, mygc, x, y, text, len); XDrawImageString (display, win, mygc, x, y, text, len);
    text ist eine beliebige Stringvariable oder -konstante, die ASCII-Text (ohne Steuerzeichen o. Ä.) enthält. len (Integer) muss die Länge von text enthalten, selbst wenn text sauber mit 0 terminiert ist. x, y sind die Koordinaten des Textes relativ zur linken oberen Fensterecke. x, y beziehen sich auf die Grundlinie der Schrift – z. B. auf die Ecke links unten vom Buchstaben E. Beide Funktionen benutzen als Textfarbe die im GC eingetragene Vordergrundfarbe.
       
    Der Unterschied der beiden Funktionen liegt darin, dass XDrawString() im Gegensatz zu XDrawImageString() nicht die Hintergrundfarbe verwendet, auf die der Grafikkontext GC eingestellt ist, sondern den Hintergrund als durchsichtig betrachtet.
       
4. Font (Speicher) wieder freigeben mit: XUnloadFont (display, font).
       

Rheinwerk Computing

14.7.2 Übersicht zu den Fonts  downtop

Wenn Sie sich einen Überblick über alle Schriftarten (Fonts) auf Ihrem System machen wollen, verwenden Sie am besten das X-Tool xlsfonts (mit einer Pipe über less). Gewöhnlich ist der Name einer Schriftart wie folgt aufgebaut:

...
-adobe-courier-medium-r-normal--8–80–75–75-m-50-iso8859–4
-adobe-courier-medium-r-normal--8–80–75–75-m-50-iso8859–9
-adobe-helvetica-bold-o-normal--10–100–75–75-p-60-iso10646–1
-adobe-helvetica-bold-o-normal—10–100–75–75-p-60-iso8859–1
...

Es gibt auch noch einige ältere Schriftarten, die nicht mit dem Minuszeichen am Anfang beginnen. Folgende Bedeutung haben die einzelnen Felder getrennt durch '-' (leeres Feld ist somit '--'):

gp  Hersteller der Schrift: adobe, sony, schumacher, b&h, bitstream, (misc)
gp  Schrifttyp-Familie: times, courier, helvetica, new century schoolbook, fixed, symbol, lucida, lucidabright, lucidatypewriter, open look glyph
gp  Dicke des Schrifttyps: bold, demibold, light, medium, clean
gp  Neigung der Schrift: r für roman, i für italic, o für oblique
gp  keine Serifen: sans
gp  Zeichenhöhe der Schrift in Pixel: 10, 12, 13, 16, 19 ...
gp  Der sog. Schriftgrad in Zehntelpunkten (= 0.023 mm), d. h. die vom Bildschirm unabhängige Zeichengröße: 100, 120, 190 ...
gp  horizontale/vertikale Auflösung (in dpi): 75–75, 100–100 ...
gp  Zeichenabstand der Schrift: p für proportional, m für monospaced

Natürlich lässt sich diese Liste der Schriftarten auch mit einer X-Funktion, nämlich mit XListFonts(), ermitteln:

    Display *display;
    char *mask;
    char **list;
    int count;
    ...
    list=XListFonts(mydisplay, mask, 1000, &count);
    ...
    XFreeFontNames(list);

mask ist ein String, womit Sie bestimmte Schriften herausfiltern können, z. B.:

gp  "*" – Alle Schriftarten auswählen
gp  "*adobe*" – Nur Schriftarten von Adobe auswählen
gp  "*italic*" – Nur Italic-Schriftarten auswählen
gp  "*times*" – Nur Schriften vom Typ Times auswählen

In count befindet sich die Anzahl der gefundenen Schriftarten, die Sie mit dem dritten Parameter begrenzen können. In diesem Fall werden max. 1000 Schriftarten ermittelt – egal wie viele noch existieren. Im Stringarray list befinden sich alle Namen, worauf Sie jetzt mit dem Index – z. B. um eine Schriftart zu laden – zurückgreifen können:

font=XLoadFont(display, list[5]);

Um den Speicher der Liste wieder freizugeben, sollten Sie die Funktion XFreeFontNames() verwenden.


Rheinwerk Computing

14.7.3 Höhe und Breite ermitteln  downtop

Um einen Text auch ordentlich auf dem Bildschirm platzieren zu können, benötigt man Informationen über die Breite und Höhe der Schrift. Die Höhe ist unabhängig vom eigentlichen Text und nur durch den Font festgelegt. Zahlreiche Größeninformationen (in Pixel) über einen Font erhalten Sie über die Struktur XFontStruct:

   Display *display;
   XFontStruct *fontinfo;
   ...
   fontinfo=XQueryFont(display,font);
   printf("ascent: %d   descent: %d\n",
      (*fontinfo).ascent, (*fontinfo).descent);

Die Struktur XFontStruct enthält u. a. die beiden Variablen ascent, welche die Höhe über der Grundlinie (mit Platz nach oben) anzeigt, und descent, die angibt, wie viel Platz nach unten hin gebraucht wird (mit Platz nach unten). Somit erhalten Sie die gesamte Höhe durch die Summe der beiden Zahlen. Mehrzeiliger Text kann einfach mit diesem Abstand ausgegeben werden.

Die Breite hängt (bei Proportionalschriften) natürlich vom konkreten Text ab. Auch hierfür gibt es eine Funktion, die ebenfalls die Struktur XFontStruct benötigt:

    XFontStruct *fontinfo;
    char *text;
    int len,width;
    ...
    width=XTextWidth(fontinfo, text,len);

Rheinwerk Computing

14.7.4 Listing mit Textausgabe  toptop

Das folgende Listing stellt eine Erweiterung des Listings vom Beispiel zuvor dar, nur dass die Funktionen, mit denen die Grafikprimitiven erstellt wurden, nun auch als Beschreibung mit ausgegeben werden. Außerdem wird mit einem rechten Mausklick ein Zufallsfont aus der Fontliste geladen, und alle (falls möglich) 255 Zeichen werden ausgegeben. Bei erneutem Rechtsklick werden wieder zufällige Fonts geladen und angezeigt. Die Anzahl der vorhandenen Fonts wird auf der Konsole ausgegeben.

/* xfont.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "my_delay.h"
#define WINDOW_WIDTH 600
#define WINDOW_HEIGHT 450
/* Funktionsprototypen */
static int create_window (void);
static void process_event (XEvent report);
static void eventloop (void);
static void close_window (void);
extern int delay (int i);
extern int time_diff (void);
static void draw_graphics (void);
static void print_text (GC, int, int, char *, char *);
static void print_font_demo (void);
/* Globale Variablen */
static unsigned int width, height;
static Display *display;
static int screen;
static int depth;
static Window win; 
/* Schriftarten */
static char *my_fonts[] = {
   "-adobe-times-bold-r-normal--18*",
   "-adobe-times-bold-r-normal--12*",
   "-b&h-lucida-medium-r-normal-*-*-180-*-*-*-*-*-*",
   "-*-times-*-*-*-*-*-240-*-*-*-*-*-*"
};
enum { ADOBE_BOLD_18, ADOBE_BOLD_12, LUCIA_NORMAL, TIMES };
/* Funktion erzeugt ein Fenster */
static int create_window (void) {
  char *window_name = "Fontdemo";
  char *icon_name   = "window";
  static XSizeHints size_hints;
  Window rootwin;
  width = WINDOW_WIDTH;
  height = WINDOW_HEIGHT;
  /* X-Sitzung öffnen */
  display = XOpenDisplay (NULL);
  /* Fehlerüberprüfung */
  if (display == NULL) {
    printf ("Verbindung zum X-Server fehlgeschlagen?!?\n");
    exit(EXIT_FAILURE);
  }
  /* Standardbildschirm eines Displays */
  screen = XDefaultScreen (display);
  /* Standardtiefe des Screens - Anzahl der Ebenen */
  depth = XDefaultDepth (display, screen);
  rootwin = RootWindow (display, screen);
  win = XCreateSimpleWindow ( display, rootwin, 10, 10,
                              width, height, 5,
                              BlackPixel (display, screen),
                              WhitePixel (display, screen) );
  size_hints.flags = PSize | PMinSize | PMaxSize;
  size_hints.min_width =  width;
  size_hints.max_width =  width;
  size_hints.min_height = height;
  size_hints.max_height = height;
  XSetStandardProperties ( display, win, window_name, icon_name,
                           None, 0, 0, &size_hints );
  XSelectInput (display, win,
                ButtonPressMask | KeyPressMask | ExposureMask );
  XMapWindow (display, win);
  return 1;
}
static void close_window (void) {
  XCloseDisplay (display);
}
static void eventloop (void) {
  XEvent xev;
  int num_events;
  XFlush (display);
  num_events = XPending (display);
  while ((num_events != 0)) {
    num_events--;
    XNextEvent (display, &xev);
    process_event (xev);
  }
}
static void process_event (XEvent report) {
  switch (report.type) {
  case Expose:      /* Expose-Event => Bild zeichnen */
    if (report.xexpose.count == 0) {
      draw_graphics ();
    }
    break;
  case KeyPress:
    printf ("Tastaturaktion\n");
    break;
  case ButtonPressMask:
    /* Rechte Maustaste gedrückt? */
    if (report.xbutton.button == 3)
      print_font_demo ();
    else
      printf ("Mausaktion\n");
    break;
  default:
    break;
  }
}
static void draw_graphics (void) {
  GC mygc;                      /* neu: Grafikkontext */
  unsigned long black, white;   /* Nummern der Farben */
  int i;
  XPoint punkte[50];            /* Punkteschar */
  XPoint poly[4];               /* 4 Punkte fuer Polygon */
  /* Ein paar Felder belegen                   */
  /* Eine Schräge mithilfe von Punkten zeichnen */
  for (i = 0; i < 50; i++) {
    punkte[i].x = 470 + i;
    punkte[i].y = 200 + i;
  }
  /* geschlossenes Dreieck */
  poly[0].x = 200;
  poly[0].y = 200;   
  poly[1].x = 300;
  poly[1].y = 300;
  poly[2].x = 400;
  poly[2].y = 200;
  poly[3].x = 200;
  poly[3].y = 200;
  /* Fenster oben drauf anzeigen */
  XMapRaised (display, win);   
  /* Farbnummern besorgen */
  black = BlackPixel (display, screen);
  white = WhitePixel (display, screen);
  /* Graphical Context erzeugen, Farben eintragen */
  mygc = XCreateGC (display, win, 0, 0);
  XSetForeground (display, mygc, black);
  XSetBackground (display, mygc, white);
  /* sicherheitshalber alles löschen */
  XClearWindow (display, win);
  /* Ein Rechteck zeichnen */
  XDrawRectangle (display, win, mygc, 10, 50, 50, 50);
  print_text (mygc, 10, 320, "1. XDrawRectangle()",
     my_fonts[ADOBE_BOLD_12]);
  /* Einen rechteckigen Bereich mit Farbe füllen */
  XFillRectangle (display, win, mygc, 110, 50, 50, 50);
  print_text (mygc, 110, 240, "2. XFillRectangle()",
     my_fonts[ADOBE_BOLD_12]);
  /* Einen Kreis zeichnen */
  XDrawArc (display, win, mygc, 210, 50, 50, 50, 0, 360 * 64);
  print_text (mygc, 210, 320, "3. XDrawArc()",
    my_fonts[ADOBE_BOLD_12]);
  /* Einen Kreisbereich füllen */
  XFillArc (display, win, mygc, 310, 50, 50, 50, 0, 360 * 64);
  print_text (mygc, 310, 240, "4. XFillArc()",
    my_fonts[ADOBE_BOLD_12]);
  /* Eine Ellipse zeichnen */
  XDrawArc (display, win, mygc, 410, 50, 60, 40, 0, 360 * 64);
  print_text (mygc, 410, 320, "5. XDrawArc()",
    my_fonts[ADOBE_BOLD_12]);
  /* Einen Ellipsenbereich füllen */
  XFillArc (display, win, mygc, 510, 50, 60, 40, 0, 360 * 64);
  print_text (mygc, 510, 240, "6. XFillArc()",
    my_fonts[ADOBE_BOLD_12]);
  /* Einen Halbkreis zeichnen */
  XDrawArc (display, win, mygc, 10, 200, 60, 40, 90*64, 180*64);
  print_text (mygc, 10, 480, "7. XDrawArc()",
    my_fonts[ADOBE_BOLD_12]);
  /* Einen Halbkreis füllen */
  XFillArc (display,win, mygc, 110, 200, 60, 40, 90*64, 180*64);
  print_text (mygc, 110, 380, "8. XFillArc()",
    my_fonts[ADOBE_BOLD_12]);
 /* ausgefuelltes Polygon bzw. Dreieck */
  XFillPolygon(display, win, mygc, poly, 4, 0, CoordModeOrigin);
  print_text (mygc, 250, 520, "9. XFillPolygon()",
     my_fonts[ADOBE_BOLD_12]);
  /* Eine schräge Linie mit Punkten */
  XDrawPoints (display, win, mygc, punkte, 50, CoordModeOrigin);
  print_text (mygc, 470, 380, "10. XDrawPoints()",
     my_fonts[ADOBE_BOLD_12]);
  print_text (mygc, 150, 590,
    "Mit rechter Maustaste zum Font-Demo",
    my_fonts[ADOBE_BOLD_18] );
  XFlush (display);
  XFreeGC (display, mygc); 
}
static void
print_text (GC mygc, int x, int y, char *string, char *myfonts){
  Font myfont;      /* Schriftarten */
  char *fname = myfonts;
  /* Schriftart laden */
  myfont = XLoadFont (display, fname); 
 /* im Grafikkontext eintragen */
  XSetFont (display, mygc, myfont);   
  XDrawString ( display, win, mygc, x, y - 200,
                string, strlen (string) );
  /* Schriftart wieder freigeben */
  XUnloadFont (display, myfont);   
}
static void print_font_demo (void) {
  int fcount;                /* Zahl der Fonts von XListFont  */
  char **fontlist;           /* Zeiger auf Feld mit Fontnamen */
  Font headerfont, myfont;   /* Textfonts                     */
  int fontnr;                /* Fontnummer                    */
  char *fname;               /* Text mit Fontnamen            */
  char clist[256];           /* 256 Zeichen                   */
  XFontStruct *fontinfo, *headerinfo;   /* Fontinformationen  */
  int headerlength;          /* Textlaenge Header             */
  int headerwidth;           /* Textbreite Header             */
  int headerheight;          /* Hoehe des Header-Fonts        */
  int fontheight;            /* Hoehe des Zufallsfonts        */
  int width;             /* Breite des Textes mit Zufallsfont */
  int i;
  GC mygc;
  mygc = XCreateGC (display, win, 0, 0);
  /* Fontliste holen */
  fontlist = XListFonts (display, "*", 5000, &fcount);
  printf ("%d Schriften gefunden!\n", fcount);
  /* Fenster loeschen */
  XClearWindow (display, win);   
  /* Schriftart fuer die Ueberschrift */
  headerfont = 
     XLoadFont (display, "-adobe-times-bold-r-normal--18*");
  headerinfo = XQueryFont (display, headerfont);
  headerheight = (*headerinfo).ascent + (*headerinfo).descent;
  for (i = 0; i < 256; i++)
    clist[i] = i;   /* 256 ASCII-Zeichen definieren */
  /* zufaelligen Font mit modulo! */
  fontnr = (rand ()) % fcount;
  /* das ist sein Name */
  fname = fontlist[fontnr];   
  /* Header schreiben:  Name des Fonts zentriert oben        */
  /*                    mit Schrifttyp = headerfont          */
  headerlength = strlen (fname);       /* Laenge des Headers */
  XSetFont (display, mygc, headerfont);/* Header-Font setzen */
  headerwidth = XTextWidth (headerinfo, fname, headerlength);
  XDrawString ( 
     display, win, mygc,        /* Header darstellen */
     (600 - headerwidth)/2, headerheight*3/2, /* x,y */
               fname, headerlength  );
  /* clist mit 256 Zeichen schreiben in neuer Schrift        */
  myfont = XLoadFont (display, fname);         /* Font laden */
  fontinfo = XQueryFont (display, myfont); /* Infos besorgen */
  XSetFont (display, mygc, myfont);       /* in GC eintragen */
  fontheight = (*fontinfo).ascent + (*fontinfo).descent;
  for (i = 0; i < 4; i++) {
    width = XTextWidth (fontinfo, &clist[64 * i], 64);
    XDrawString (
       display, win, mygc,
       (600 - width)/2, (3*headerheight+i*fontheight),
        &clist[64*i], 64 );
  }
  print_text (mygc, 150, 590,
     "Mit rechter Maustaste neue Schrift laden",
     my_fonts[ADOBE_BOLD_18]);
  XUnloadFont (display, myfont); 
  XFreeGC (display, mygc);
}
 
 int main (int argc, char **argv) {
  int quit = 0;
  int pause = 0;
  int td;
  create_window ();
  gettimeofday (&st, NULL);
  while (!quit) {
    gettimeofday (&rt, NULL);
    td = time_diff ();
    pause = delay (FRAME_LEN - td + pause);
    st = rt;
    eventloop ();
  }
  close_window ();
  return EXIT_SUCCESS;
}

Das Programm bei der Ausführung:

$ gcc -o xfont xfont.c -L/usr/X11R6/lib -lX11
$ ./xfont

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 14.3    Textausgabe im X-Fenster



Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 14.4    Ausgabe eines kompletten Zeichensatzes


Im Beispiel sehen Sie übrigens auch, warum es unbedingt nötig ist, in der Praxis die Breite der Fonts zu ermitteln. Bei der zufälligen Ausgabe von Fonts werden viele größere Schriften nicht komplett am Bildschirm angezeigt. Man sollte die Breite der einzelnen Zeichen addieren und darauf achten, dass dabei die Breite des Fensters nicht überschritten wird. Sobald die Summe der einzelnen Zeichen mehr als die Breite des Fensters ist, sollte man in der nächsten Zeile mit der Ausgabe fortfahren.

 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern