Диагональные линии в FoxPro/WINDOWS

Дуг Бланк

Грустно, но это правда. Вы не можете нарисовать диагональную линию в FoxPro. Я пытался даже использовать Windows API, и, действительно, вы можете нарисовать все что угодно в окне FoxPro, только FoxPro ничего не знает об этом. Следовательно, после того как вы закроете окно и снова откроете его, линия пропадет. Стоит вам поместить другое окно поверх того, где нарисована линия, и она не будет перерисована. В итоге я пришел к решению, описанному ниже. Программа довольно неплохо справляется с задачей рисования произвольных линий. При необходимости можно отрегулировать размеры точки. Эти параметры необходимы, так как при трансляции целых чисел в экранные координаты нужно учитывать особенности графического интерфейса.

Процедура вызывается так:

=drawline(1,5,11,30,.T.)

Используя предложенный метод, вы можете рисовать круги, кривые и т. п. Поместите приведенную функцию в вашу программу или закоментируйте первую строку и сохраните файл как DRAWLINE.PRG. Это не самый быстрый или самый гладкий подход, но он работает. Скорее всего вам не удастся сделать линию тоньше, это связано с трансляцией расчетных значений в экранные координаты. Вы можете изменить цвета посредством функции RGB() или даже добавить структуру CASE для использования всех возможных цветов, добавления теней и т. д.

FUNCTION drawline
PARAMETER x1,y1,x2,y2,COLOR
PRIVATE x,y,B,slope
#DEFINE xdotsize (.2)
#DEFINE ydotsize (.5)
#DEFINE pensize (3)
#DEFINE penlen (.7)
IF m.y1 = m.y2 && вертикальная линия
   IF x1 < x2
      IF COLOR
         @m.x1,m.y1 TO m.x2,m.y1 ;
            PEN pensize COLOR ;
            RGB(0,255,0,255,255,255) ;
            STYLE "T"
      ELSE
         @m.x1,m.y1 TO m.x2,m.y1 ;
            PEN pensize COLOR ;
            RGB(255,0,255,255,255,255) ;
            STYLE "T"
      ENDIF
   ELSE
      IF COLOR
         @m.x2,m.y1 TO m.x1,m.y1 ;
            PEN pensize COLOR ;
            RGB(0,255,0,255,255,255) ;
            STYLE "T"
      ELSE
          @m.x2,m.y1 TO m.x1,m.y1 ;
            PEN pensize COLOR ;
            RGB(255,0,255,255,255,255) ;
            STYLE "T"
      ENDIF
   ENDIF
ELSE
   m.slope = (m.x1 - m.x2)/(m.y1 - m.y2)
   m.b = m.x1 - (m.slope   * m.y1)
   IF ABS((m.x1 - m.x2) / xdotsize) > ;
      ABS((m.y1 - m.y2) / ydotsize)
      FOR m.x = m.x1 TO m.x2 STEP xdotsize * ;
         IIF( m.x1 > m.x2, -1, 1)
         m.y = (m.x - m.b) / m.slope
         IF COLOR
            @m.x,m.y TO m.x,m.y+penlen PEN ;
               pensize COLOR ;
               RGB(0,255,0,255,255,255) ;
               STYLE "T"
         ELSE
            @m.x,m.y TO m.x,m.y+penlen PEN ;
               pensize COLOR ;
               RGB(255,0,255,255,255,255) ;
               STYLE "T"
         ENDIF
      ENDFOR
   ELSE
   FOR m.y = m.y1 TO m.y2 ;
    STEP ydotsize * IIF( m.y1 > ;
    m.y2, -1, 1)
      m.x = (m.slope * m.y) + m.b
      IF COLOR
         @m.x,m.y TO m.x,m.y+penlen PEN ;
            pensize COLOR ;
            RGB(0,255,0,255,255,255);
            STYLE "T"
      ELSE
         @m.x,m.y TO m.x,m.y+penlen PEN ;
            pensize COLOR ;
            RGB(255,0,255,255,255,255) ;
            STYLE "T"
      ENDIF
   ENDFOR
 ENDIF
ENDIF
RETURN

Как сохранить структуры таблиц в каталоге Читаем структуры всех таблиц в каталоге и записываем их в текстовый файл:

* STRSAV.PRG
SET TALK OFF
CLEAR ALL
PRIVATE ALL LIKE l
** Просим пользователя выбрать каталог
ldirectory = GETDIR(CURDIR(), ;
  "Select a directory containing tables:")

* убедимся, что каталог выбран
IF !EMPTY(ldirectory)
*
* считываем имена всех таблиц в массив
   lhits = ADIR(ltables, ldirectory + "*.DBF")
*
* убедимся, что в каталоге есть таблицы
IF lhits == 0
  WAIT WINDOW ;
    "No tables found in " + ldirectory
ELSE
  WAIT WINDOW "Processing tables..." NOWAIT
SELECT 0
*
* создаем временную таблицу
CREATE CURSOR ;
  WORK (filename c(8), struclist m(10))
*
* обрабатываем каждую таблицу в каталоге
FOR lcount = 1 TO lhits
*
* создаем имя временного файла
   ltempfile = SYS(3) + ".TXT"
*
* строим полный путь к файлу 
* и открываем таблицу
   lfilespec = ldirectory + ltables[lCount, 1]
   SELECT 0
   USE (lfilespec)
*
* записываем информацию о структуре таблицы 
* во временный файл
   DISPLAY STRUCTURE NOCONSOLE ;
    TO FILE (ltempfile)
*
* добавляем новую запись для данной таблицы
   INSERT INTO WORK (filename) ;
     VALUES (ltables[lCount,1])
*
* закрываем таблицу
   USE
   SELECT WORK
*
* загружаем временный файл в memo-поле
   APPEND MEMO struclist FROM (ltempfile)
*
* уничтожаем временный файл
   DELETE FILE (ltempfile)
*
* сюда можно поместить дальнейшую обработку
ENDFOR
GO TOP
* это самый простой способ 
* писать в текстовый файл
SET TEXTMERGE ON
SET TEXTMERGE TO STRUC.txt NOSHOW
\Table Structure Listing      \----------------
*
* для каждой записи выводим 
* содержимое memo-поля в текстовый файл
      SCAN
\<>
      ENDSCAN
      SET TEXTMERGE TO
      SET TEXTMERGE OFF
      USE
      WAIT WINDOW ALLTRIM(STR(lhits)) + ;
       " tables processed!"NOWAIT
   ENDIF
ENDIF
RETURN

Как сохранить определения индексов и фильтров для таблиц в текущем каталоге

Эли Линков

* INDEXSAV.PRG
* Эта программа может быть использована 
* для создания справочника 
* по всем индексам и фильтрам в каталоге 
* проекта. Таблица, куда записывается 
* информация, называется DBINFO.DBF.
*       Структура справочника
*       поле   dbfname    12 символов
*       поле   infomemo   memo
*
* В memo-поле помещается имя индекса, 
* выражение индексации и дополнительное 
* ограничение индексного выражения
* в виде <имя индекса>/<выражение>%<фильтр>,
* определение одного индекса занимает 
* строку в memo-поле
*
* Программу следует запускать 
* когда приложение готово к инсталляции,
* она создаст справочник и 
* соответствующий FPT-файл.
* Этот справочник нужно хранить 
* в "системном" каталоге приложения
* вместе с исполняемой версией 
* программы INDEXMAK.
* INDEXMAK.EXE должна быть доступна 
* только через меню администратора
* и не должна появляться как пиктограмма 
* в окне Program Manager.
* Для восстановления индексов 
* нужно запустить программу INDEXMAK.EXE


CLOSE DATABASES
* Следующие две строки указывают 
* на системные каталоги проекта
datapath =  ;
  GETDIR("",'Where the indexed tables') 
workpath =  ;
  GETDIR("",'Where the system EXE is')

IF NOT FILE(workpath + "dbfinfo.dbf")
   SET DEFAULT TO (workpath)
   * создаем таблицу-справочник 
   * (используется программой INDEXMAK.PRG)
   CREATE TABLE dbfinfo ;
    (dbfname C(12), infomemo m)
ENDIF

SET DEFAULT TO &datapath
DIMENSION filelist(1)
=ADIR(filelist,"*.dbf")
CLOSE data
set DEFAULT TO &workpath
SELECT 0
USE dbfinfo EXCLUSIVE
SET SAFETY OFF
ZAP
SET SAFETY ON
APPEND FROM ARRAY filelist
RELEASE filelist
GO TOP
SET DEFAULT TO &datapath

SCAN
   TEXT = ALLTRIM(dbfname)
   IF TEXT = "DBFINFO.DBF"
   ELSE
      REPLACE dbfname ;
        WITH LEFT(TEXT,LEN(TEXT) - 4)
      SELECT 0
      USE  ALLT((dbfinfo.dbfname)) EXCLUSIVE
      DIMENSION taglist(1,3)
      indexstr = ""
      arrct = 1
      DO WHILE NOT EMPTY(TAG(arrct))
         taglist(arrct,1) = TAG(arrct)
         * имя индекса
         taglist(arrct,2) = SYS(14,arrct)
         * выражение индексации
         taglist(arrct,3) = SYS(2021,arrct)
         * фильтр индексации (если есть)
         arrct = arrct + 1
         DIMENSION taglist(arrct,3)
      ENDDO
      SELECT dbfinfo
      FOR x = 1 TO arrct - 1
         indexstr=indexstr+taglist(x,1) ;
            +"/"+taglist(x,2);
            +"%"+taglist(x,3)+CHR(13)
      ENDFOR
      REPLACE infomemo WITH indexstr
   ENDIF
ENDSCAN

SET DEFAULT TO &workpath
CLOSE DATA



PROCEDURE INDEXMAK
* indexmak.prg
* Эта программа используется 
* для восстановления индексов
* в том случае, если таблицы проекта 
* оказались повреждены.

* Программа использует справочник DBFINFO.DBF,
* созданный программой INDEXSAV.PRG, 
* для восстановления имен индексов,
* выражений индексации и фильтров индексов.
*
* Программу нужно поместить в виде 
* исполняемого файла и дать доступ к ней 
* только администратору системы.
*
CLOSE DATABASES
* путь к "системному" каталогу проекта 
* (укажите свой путь)
datapath =  "C:\sxc\sxcbuild\"
workpath = "c:\sxc\sxcmaint\"
SET DEFAULT TO &workpath
SELECT 0
USE dbfinfo EXCLUSIVE
SET SAFETY OFF
GO TOP
SET DEFAULT TO &datapath

SCAN
   TEXT = ALLTRIM(dbfname)
   IF TEXT = "DBFINFO.DBF"
   ELSE
      SELECT 0
      USE (dbfinfo.dbfname) EXCLUSIVE
      DELETE TAG ALL
      memct = 1
      fred = dbfinfo.infomemo
      IF NOT EMPTY(fred)
         DO WHILE NOT EMPTY ;
          (MLINE(dbfinfo.infomemo,memct))
            fred = ALLTRIM ;
              (MLINE(dbfinfo.infomemo,memct))
            colno1 = AT("/",fred)
            colno2 = AT("%",fred)
            tagfield = LEFT(fred,colno1 - 1)
            * имя индекса
            tagname = SUBSTR(fred,colno1 + 1,;
               (colno2 - colno1 - 1)) 
            * выражение индексации
            tagfilt = ALLTRIM ;
              (RIGHT(fred,LEN(fred) - colno2))
            * фильтр индексации
            IF tagfilt <> ""
               INDEX ON &tagfield ;
                 FOR &tagfilt TAG &tagname
            ELSE
               INDEX ON &tagfield TAG &tagname
            ENDIF
            memct = memct + 1
         ENDDO
      ENDIF
   ENDIF
ENDSCAN

SET DEFAULT TO &workpath
SET SAFETY ON
CLOSE DATA

Пароли

* Пример 1
* (Брайан Копеланд /Brian Copeland/) 

* Это пример использования INKEY() 
* для ввода пароля и вывода '*' в поле.

CLEAR
mpassword=''mshowpass=''

@ 10,10 GET mshowpass DEFAULT '' ;
  SIZE 1,10 WHEN checkpass()
READ

PROCEDURE checkpass
DO WHILE .T.
   mkey=INKEY(0)
   DO CASE
      CASE mkey=13         
* нажата ENTER
         EXIT
      CASE BETWEEN(mkey,48,57)         
* это число
         mpassword=mpassword+CHR(mkey)
         mshowpass = mshowpass+'*'
      CASE BETWEEN(mkey,97,122)         
* это буква в нижнем регистре
         mpassword=mpassword+CHR(mkey)
         mshowpass = mshowpass+'*'
      CASE BETWEEN(mkey,65,90)         
* это буква в верхнем регистре
         mpassword=mpassword+CHR(mkey)
         mshowpass = mshowpass+'*'
      CASE mkey=127         
* нажата backspace
         mpassword=;
           LEFT(mpassword,LEN(mpassword)-1)
         mshowpass=;
           LEFT(mshowpass,LEN(mshowpass)-1)
   ENDCASE
   SHOW GETS
ENDDO
CLEAR READ


* Пример 2  (Р. Премкумар /R. Premkumar/)
* 
* Процедура проверки ввода пароля:
* если пароль верен, возвращает .t.,
* иначе возвращает .f. 
* или включает системы защиты (сирену)

* n = максимальная длина пароля, 
*   по вашему усмотрению
* c = строка, которая появляется 
*   по мере ввода пароля
*   (вместо звездочек вы можете увидеть текст 
*   "С добрым утром", который появляется 
*   по мере ввода пароля
* t = заголовок окна 

PROCEDURE password
PARAMETERS N,C,t
PRIVATE ALL

IF (PARA()>0 AND TYPE('n') #'N') OR (PARA()>1 ;
  AND TYPE('c') #'C') OR ;
  (PARA()>2 AND TYPE('t') #'C')
    WAIT WINDOW NOWAIT ;
    'Usage : ? PASSWORD( [ <length> ' +;
    '[, <display string> [, <title> ]]] )'
   * в программе вы можете вызвать 
   * эту функцию как: a=password()
   RETURN
ENDIF

IF PARA()=0
   N=7   
* длина пароля по умолчанию. 
* Используется при вызове функции 
* без параметров
ENDIF


IF PARA()<3
   t='ENTER PASSWORD' && Заголовок по умолчанию
ENDIF

DEFINE WINDOW paswrd  DOUBLE TITLE t ;
   FROM 11,IIF(MAX(N,LEN(t))<10,30,CEIL ;
    (35-MAX(N,LEN(t))/2)) ;
   TO 13,IIF(MAX(N,LEN(t))<10,50,;
    CEIL(45+MAX(N,LEN(t))/2))

ACTIVATE WINDOW paswrd
SET COLOR TO x/N
cd=IIF(PARA()<2,REPL('*',N),PADR(C,N,'.'))  
* по умолчанию выводим звездочки
ps=""

FOR i=1 TO N
   @0,5+I
   p=INKEY(0)
   DO CASE
      CASE LAST()=127 && backspace
         IF i>1
            @0,5+i-1 SAY " "
            ps=LEFT(ps,LEN(ps)-1)
         ENDIF
         i=i-2
         i=IIF(i<0,0,i)
      CASE LAST()=13  && Return
         EXIT
      OTHERWISE
         @0,5+i SAY SUBSTR(cd,i,1) COLOR W/N
         ps=ps+CHR(p)
   ENDCASE
ENDFOR

SET COLOR TO
RELEASE WINDOW paswrd
RETURN ps
Hosted by uCoz