Zmiana ustawień drukarki w rejestrze

0

Nie mogę od kilku dni poradzić sobie z problemem. W procedurze ustawdruk zmieniam ustawienia drukarki w rejestrze systemowym i ta procedura działa mi dobrze. Chodzi o to, że poniższy kod drukuje mi wszystko z ustawieniami ustawdruk(2). Dopiero jak dam ShowMessage i odklikuje OK to wszystko jest w porządku. Wszystko fajnie ale przy 1000 stron jest to niedopuszczalne aby 2000 razy klikać myszką. Próbowałęm spowolnić przez sleep z dużymi wartościami i nie działa prawidłowo, a ShowMessage nawet szybko klikając zawsze działa dobrze. Jakieś pomysły ? Dodam, że jestem amatorem na poziomie TurboPascala sprzed 15 lat :)

for i := start to stron do
    begin
        if CheckBox1.Checked then
              begin
              ustawdruk(1);
              acropdf1.printPages(i,i);
              postep(i);
            //  ShowMessage('Wydrukowano 1');
              end;

        if CheckBox2.Checked then
              begin
              ustawdruk(2);
              acropdf2.printPages(i,i);
              postep(i);
             // ShowMessage('Wydrukowano 2');
              end;
0

Jeśli wywołanie ShowMessage poprawia sprawę to prawdopodobnie ```
Application.ProcessMessages

Jeśli dobrze rozumiem to masz 2 opcje wyboru dla ustawienia drukowania. Jeśli tak to zmodyfikował bym trochę ten kod. Obecnie można np. nie wybrać żadnego chekboxa (żadne ustawienia nie zostaną wczytane) albo zaznaczyć oba (strony będą drukowane podwójnie z obydwoma ustawieniami). Ja bym napisał coś takiego:
```delphi
for i := start to stron do
begin
 case RadioGroup.ItemIndex of
  0 : begin
         ustawdruk(1);
         acropdf1.printPages(i,i); 
       end;
  1 : begin
          ustawdruk(2);
          acropdf2.printPages(i,i);
       end;
 end;
postep(i);
Application.ProcessMessages;
end;
0

Nie działa Application.ProcessMessages;

Dobrze działa kod:

ustawdruk(1);  // tu ustawiam ilość kopii oraz format strony i zapisuję do rejestru
acropdf1.printPages(i,i);
ShowMessage('Wydrukowano 3');
ustawdruk(2); // tu ustawiam ilość kopii oraz format strony i zapisuję do rejestru
acropdf2.printPages(i,i);
ShowMessage('Wydrukowano 3');

a taki nie dział:

ustawdruk(1);  // tu ustawiam ilość kopii oraz format strony i zapisuję do rejestru
acropdf1.printPages(i,i);
Application.ProcessMessages;
ustawdruk(2); // tu ustawiam ilość kopii oraz format strony i zapisuję do rejestru
acropdf2.printPages(i,i);
Application.ProcessMessages;

Inaczej spytam. Czy jest jakiś sposób aby programowo kliknąć OK w ShowMessage ? Ewidentnie gdy jest interakcja z użytkownikiem kod działa. Jeśli tego nie ma wszystko drukuje się z ustadruk(2).

0

Wracając do Twojego pierwszego postu, co konkretnie masz ustawione na formatce odnośnie checkboxów? Które są zaznaczone? Skoro ustawienia wydruku masz obsłużone w procedurze

ustawdruk(x);

to czemu masz różne odwołania w

acropdf1.printPages(i,i);

i

acropdf2.printPages(i,i);

Nie wiem też co robisz w

ustawdruk(x);

Debugowałeś kod i sprawdzałeś co się dzieje w kodem przy zastosowaniu ```
ShowMessage

Interakcja z użytkownikiem to jedynie opóźnienie wykonania kodu, nie słyszałem żeby wywołanie komunikatu wpłynęło na działanie aplikacji. Spróbuj jeszcze coś takiego zamiast ```
Application.ProcessMessages;
``` na końcu.
```delphi
for i := 0 to 5 do
begin
  Sleep(5);
  Application.ProcessMessages; 
end;
0

Nie pomogło. Wyobraźmy sobie, że chcę wydrukować notes z okładką, każdy inny. W jednym PDF mam okładki 50str, w drugim pdf mam kartki 50str.
Wydruk ma wyglądać 1 okładka, 25 kartek, 1 okładka, 25 kartek. Okładka i kartki idą z innych podajników. Mam dwa różne odwołania bo mam dwa różne pdf,y. W zmiennej Buffer1 i Buffer2 mam zapisane ustawienia dla podajnika1 i podajnika2.

Procedura ustawdruk wygląda tak i działa:

procedure ustawdruk(tacka:integer);
var
Reg : TRegistry;
begin
  case tacka of
  1:
    begin
        Reg := TRegistry.Create;
        if Reg.OpenKey('Printers\DevModePerUser', False) then
          begin
            Reg.OpenKey('Printers\DevModePerUser', False);
            Reg.WriteBinaryData(drukarka, Buffer1, SizeOf(Buffer1));
           end
          else
            ShowMessage('Błąd! Nie ma klucza "Printers\DevModePerUser" w rejestrze.');
        Reg.Free;
    end;
  2:
    begin
        Reg := TRegistry.Create;
        if Reg.OpenKey('Printers\DevModePerUser', False) then
          begin
            Reg.OpenKey('Printers\DevModePerUser', False);
            Reg.WriteBinaryData(drukarka, Buffer2, SizeOf(Buffer2));
          end
          else
            ShowMessage('Błąd! Nie ma klucza "Printers\DevModePerUser" w rejestrze.');
        Reg.Free;
    end;
0

No to może

acropdfX.printPages(i,i);

nie bierze aktualnie zmienionych wartości z rejestru. Ja bym spróbował jeszcze dać Application.ProcessMessages; bezpośrednio po ustawdruk(x); a jeśli dalej będzie nie tak to może to rozwiązanie da radę: https://stackoverflow.com/questions/37404305/how-to-refresh-registry-keys-without-reboot

0

Dalej to samo i jeden i drugi pomysł.

0

Był na tym forum już problem dotyczący AcroPDF. Dotyczył czego innego ale może rozwiązanie będzie to samo. Wtedy komponent zabierał autofocusa z innych komponentów. Może jest tak, że aplikacja nie jest w stanie dostać się do nowych wartości rejestru właśnie przez takie zachowanie a MessageBox wymusza 'zdjęcie' autofocusa z komponentu. Ja bym spróbował jeszcze czegoś takiego po wywołaniu ustawdruk(x);

AcroPDF1.Enabled := False;
Application.ProcessMessages;
AcroPDF1.Enabled := True;

Więcej pomysłów chyba na teraz już nie mam.

0

To samo. Drukuje zawsze ustawdruk(2)

0

Doszedłem po wielu testach do tego, że trzeba poczekać określony czas na zbuforowanie się wydruku. Te czasy są różne. Okienka z Dialogs wyświetlają się dopiero jak operacja drukowania się zakończy a inne operacje lecą dalej po druku. Program dział mi dobrze kiedy dam np. InputBox. Kiedy dam np. sleep(1000). Pierwsze 5 stron idzie prawidłowo a potem już jest wszystko z ustawienia 2. Potrzebuję wstawić coś co poczeka aż wydruk z acropdf1.printPages(i,i) się zakończy i program pójdzie dalej. Dobrze realizuje to jakiegolwiek okienko dialogowe. Tylko jak takie okno wyświetlić na 0,00001s ?

3 dzień nad tym siedzę i nic ...

0

Ten temat na pewno mi pomoże bo mogę otworzyć okno dialogowe i je zamknąć, ale .... jest to dla mnie za skoplikowane :)
Własne okna dialogowe

Ktoś pomoże ?

Potrzebuję otworzyć okno dialogowe, nic nie wpisywać i po 0,001s je zamknąć.

0

nie znam AcroPdf, ale może ma jakąś własność/metodę pozwalającą sprawdzić status buforowania
coś np w ten deseń :

 while acropdf1.isprinting do
    sleep(100);

do powyższej pętli można by jeszcze dodać jakiś warunek na maksymalną liczbę cykli oczekiwań, bo jeśli sam proces drukowania przywiesi się to będzie zwiecha aplikacji

0

Okno dialogowe ma to do siebie że czeka na reakcję użytkownika. Możesz wywołać okno ale programowo go raczej nie zamkniesz, bo kod stanie na wywołaniu okna i będzie czekał na operacje na oknie.
Chciałem napisać już to wcześniej ale ja bym zastanowił się nad rozwiązaniem tego typu: https://stackoverflow.com/questions/3387813/c-sharp-acropdf-always-print-on-first-printer a to tylko jedna z wielu podobnych opinii które znalazłem na temat AcroPDF.

0

@Clarc

Okno dialogowe ma to do siebie że czeka na reakcję użytkownika.

można by coś pokombinować z odpaleniem pobocznego wątku który wyręczył by użytkownika i sam zamknął okno po jakimś czasie.
Tyle że coś takiego trudno zrobić z systemowym oknem dialogowym opakowanym w showmessage ponieważ nie ma do niego żadnego dostępu. Trzeba by zrobić własne okno dialogowe dziedziczące z Tform i przekazać do wątku referencję do takiego okna

EDT...
nawet wątek nie jest potrzebny, wystarczy zwykły Timer na formie aktywowany w onshow, który zamknie okno (formę) po zadanym czasie

0

nie wnikam w problem, ale możesz zrobić samozamykalny komunikat używając CreateMessageDialog (np.z timerem odliczającym do zera):
title

0

@trzeźwy rycerz

Potrzebuję otworzyć okno dialogowe, nic nie wpisywać i po 0,001s je zamknąć.

stwórz własne okno dialogowe dziedziczące z Tform, umieść na nim timera aktywowanego w onshow formy(okna), który po zadanym czasie zamknie formę

0
Clarc napisał(a):

Okno dialogowe ma to do siebie że czeka na reakcję użytkownika. Możesz wywołać okno ale programowo go raczej nie zamkniesz, bo kod stanie na wywołaniu okna i będzie czekał na operacje na oknie.

Nawet jeśli okno zostanie wyświetlone za pomocą metody ShowModal, to i tak można je zamknąć kodem nie znajdującym się wewnątrz klasy tego okna, zanim manualnie zrobi to użytkownik. Można do tego celu odpalić wątek poboczny, ale też zwykły timer wystarczy.

Pytanie tylko po co?

Do sprawdzenia czy dokument został wydrukowany czy nie, system posiada stosowne funkcje, które pozwalają sprawdzić kolejkę zadań drukarki i ich stan. Do poczytania:

0

@furious programming:
myślę że problem sprawiają systemowe okna dialogowe opakowane np. w procedurę showmessage. Nie ma do nich żadnego dostępu z poziomu aplikacji , tym samym nie da się ich zamknąć z wątku pobocznego albo z timera

0

Jest do nich dostęp, tyle że nie bezpośredni. To zwykłe okno, więc posiada uchwyt, a skoro ma uchwyt to można go pobrać za pomocą systemowej enumeracji okien i wykorzystać. Zresztą pytaczowi nie jest potrzebne okno z ShowMessage – wystarczy mu byle jakie okno, byle faktycznie zostało wyświetlone.

Co i tak nie zmienia faktu, że jest to dziwne obejście, a nie sensowne rozwiązanie problemu.

To nie wyświetlenie okna naprawia drukowanie, a przerwa, jaka ma być za jego pomocą uzyskana pomiędzy wysyłaniem zadań do drukarki. Zamiast kombinować z formularzami wytracającymi czas, należy w pętli sprawdzać kolejkę zadań drukarki i przejść do wysłania kolejnego zadania, jeśli poprzednie zostanie zakończone.

0

@furious programming:
jasne, każde okno ma swój uchwyt, ale procedura showmessage nie daje do niego dostępu
pisałem że autor wątku, jeśli ma taką potrzebę, powinien stworzyć własne okno dialogowe , a w nim może zrobić wszystko, w tym samoczynne zamykanie

0

Nie musi dawać dostępu, skoro można go uzyskać kilkoma linijkami kodu, używając funkcji z systemowego API. W ten sposób da się manipulować dowolnymi oknami i ich zawartością.

0

@furious programming:
więc się zgadzamy, w tej sytuacji okno trzeba samemu "wykodzić" nie posługując się procedurą "showmessage"

0

Dziękuję za odpowiedzi. Będę walczył z pomysłami. Faktycznie okno dialogowe to tylko substytut wymyślony gody sobie je wstawiałem aby testować jak działa program i stwierdziłęm, że z tym oknem działa a bez niego nie. Faktycznie najlepszym pomysłem jest spradzenie stanu drukarki, nie wiem czy sobie poradzę, ale jestem zawzięty i walczę dalej.

0

Znalazłem taką funkcję. Jak ją wywołać w programie ? Jakie parametry ?

function MessageDlgTimed(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
const
  closePeriod = 2 * 1000;
var
  timerCloseId: UINT_PTR;
 
  procedure CloseMessageDlgCallback(AWnd: HWND; AMsg: UINT; AIDEvent: UINT_PTR; ATicks: DWORD); stdcall;
  var
    activeWnd: HWND;
  begin
    KillTimer(AWnd, AIDEvent);
 
    activeWnd := GetActiveWindow;
 
    if IsWindow(activeWnd) AND IsWindowEnabled(activeWnd) then
      PostMessage(activeWnd, WM_CLOSE, 0, 0);
  end; (*CloseMessageDlgCallback *)
 
begin
  timerCloseId := SetTimer(0, 0, closePeriod, @CloseMessageDlgCallback);
 
  result := MessageDlg(Msg, DlgType, Buttons, HelpCtx);
 
  if timerCloseId <> 0 then
    KillTimer(0, timerCloseId);
end;
0

Działa !!!!!!!!!

Wywołanie oczywiście proste, ale dla amatora nie koniecznie. Dziękuję wszystkim

Wywołanie dla potomnych:

MessageDlgTimed('Tekst przykładowy', mtInformation, [mbOK], -1);

1 użytkowników online, w tym zalogowanych: 0, gości: 1