It seems that on Win7 changing the TOpenDialog.InitialDir doesn't work, when the new directory is on a different drive, than the current directory.
e.g.: I want to change my InitialDir from 'C:\program files\MyApp' to 'D:\test\MyAppData'
Is that a known issue, or only on my computer?
I already tried the same thing, as mentioned in the following post, but without any success:
Changing the directory of Delphi OpenDialog
EDIT:
I am using DelphiXE on Win7 32 Bit
The path/dir is correct: So, when I copy that path from code and past it into the 'File Name' field of that Dialog itself and I press ENTER, then the Dialog switches to that directory. Only, in my code it is not working.
UPDATE:
I found the problem. If the path contains some path commands like ..\ the TOpenDialog.InitialDir is not able to resolve that. Use TPath.GetFullPath(...) to make it clean.
I have tested on a Delphi XE, it runs fine... I have done this:
Put a new form:
object Form4: TForm4
Left = 0
Top = 0
Caption = 'Form4'
ClientHeight = 204
ClientWidth = 447
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 24
Top = 40
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Edit1: TEdit
Left = 120
Top = 42
Width = 121
Height = 21
TabOrder = 1
Text = 'D:\'
end
object OpenDialog1: TOpenDialog
InitialDir = 'C:\'
Left = 120
Top = 72
end
end
And its source code:
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm4 = class(TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.Button1Click(Sender: TObject);
begin
OpenDialog1.InitialDir := edit1.text;
OpenDialog1.Execute;
end;
end.
Regards
I don't have any problem changing InitialDir, either through object inspector or runtime (Win7 with Delphi 2010). Try doublechecking if the directory you try to change to is correctly typed.
Related
I have been using Delphi 6 for a very long time, and I recently started using version Delphi DX Rio 10.3.
Against all my expectations, it seems to me that loading items on standard controls (ComboBox, Listbox and so on) in DX RIO is significantly slower (at runtime) than in D6 (both in DEBUG and RELEASE mode, after activating all optimizations).
I tried using BeginUpdate / EndUpdate, without changing the speed difference between the environments.
I would like to ask if anyone has any suggestions for improving DX 10.3 Combobox/Listbox performances. The specific problem I'm trying to solve in my real application is to load some dozens of items in 10-20 combos/listboxes controls on my form.
I wrote a very simple test for a standard COMBO. The same program works in both D6 and DX RIO.
On my development machine (Win 10 pro) the program compiled with D6 takes about 1 second, while the program compiled with DX RIO takes about four times as much.
Many thanks in advance for your answers.
{$A+,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
cb: TComboBox;
txt_count: TLabel;
btn: TButton;
procedure btnClick(Sender: TObject);
end;
var Form1: TForm1;
implementation
{$R *.dfm}
var dt_start_timer : TDatetime;
procedure start_timer;
begin
dt_start_timer := now
end;
function delta_timer_msec : longint;
begin
result := round((now - dt_start_timer) * 24*60*60*1000)
end;
procedure execute(father : TForm;cb : TComboBox;txt : TLabel;bo_disable_update : boolean);
const
MAX = 100;
ITEMS_COUNT = 1000;
var i, j : integer;
begin
start_timer;
if bo_disable_update then cb.Items.BeginUpdate;
for i := 1 to MAX do begin
cb.Items.Clear;
for j := 1 to ITEMS_COUNT do cb.Items.Add('text-' + intToStr(j))
end;
if bo_disable_update then cb.Items.EndUpdate;
txt.Caption := intToStr(delta_timer_msec) + ' msecs'
end;
procedure TForm1.btnClick(Sender: TObject);
begin
execute(self, cb, txt_count, {disable_update}TRUE)
end;
end.
object Form1: TForm1
Left = -6
Top = 117
Width = 449
Height = 350
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object txt_count: TLabel
Left = 198
Top = 32
Width = 44
Height = 13
Caption = 'txt_count'
end
object cb: TComboBox
Left = 42
Top = 28
Width = 145
Height = 21
ItemHeight = 13
TabOrder = 0
Text = 'cb'
end
object btn: TButton
Left = 24
Top = 70
Width = 251
Height = 139
Caption = 'btn'
TabOrder = 1
OnClick = btnClick
end
end
I have a need for a user to be able to select an existing read-only file from a save dialog. I thought you could do this with a judicious selection of the TSaveDialog options but I can't make it happen. If I select a R/O file, as soon as I hit the Save button I get the message:
Read-only.txt
This file is set to read-only.
Try again with a different file name.
I imagined the option bit ofNoReadOnlyReturn would control this, but it seems to have no effect.
What am I missing?
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
-
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
SaveDialog1: TSaveDialog;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
if SaveDialog1.Execute then
begin
Windows.Beep (1000, 300) ;
end ;
end ;
end.
-
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 69
ClientWidth = 195
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 56
Top = 18
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object SaveDialog1: TSaveDialog
FileName = 'Read-only.txt'
InitialDir = 'C:\Users\Ross\Documents\RAD Studio\Projects'
Options = [ofHideReadOnly, ofNoReadOnlyReturn, ofEnableSizing]
Left = 16
Top = 16
end
end
The issue is not with TSaveDialog itself, but with the underlying Win32 GetSaveFileName()/IFileSaveDialog APIs that TSaveDialog uses internally. They simply do not allow a read/only file to be the result of a "save" dialog.
That being said, IFileSaveDialog does provide a possible (albeit ugly) workaround. If you enable the dialog's FOS_OVERWRITEPROMPT flag, then selecting an existing file will prompt the user if the file can be overwritten before closing the dialog. The IFileDialogEvents interface has an OnOverwrite event, which is fired before that prompt appears (and can return FDESVR_ACCEPT to skip the prompt completely). So, in that event, you could remove the file's FILE_ATTRIBUTE_READONLY attribute before the dialog is closed. However, the dialog will still display the same "This file is set to read-only" error message and refuse to close (presumably because it has checked the attribute before firing the OnOverwrite event), but if you then select the same file again, the attribute will have been cleared and the dialog will accept the file (that is the ugly part - you would have to train your managers to ignore that error and retry).
GetSaveFileName() has an ofOverwritePrompt flag, but no event for overwrite prompting.
That being said, TSaveDialog does not expose access to the IFileSaveDialog.OnOverwrite event when it uses IFileSaveDialog internally, but you can use TFileSaveDialog instead, which does.
I've got a very simple program that uses DSPack from within Delphi 2010. I have a form with a TFilterGraph and a TVideoWindow. The video plays and renders nicely. I can't seem to figure out how to make the video loop back to the beginning when it ends.
How do you make a video automatically loop using DSPack?
Code
unit Unit21;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DSPack, ExtCtrls;
type
TForm21 = class(TForm)
FilterGraph1: TFilterGraph;
OpenDialog1: TOpenDialog;
Button1: TButton;
Button2: TButton;
Panel1: TPanel;
VideoWindow1: TVideoWindow;
Panel2: TPanel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form21: TForm21;
implementation
{$R *.dfm}
procedure TForm21.Button1Click(Sender: TObject);
begin
OpenDialog1.InitialDir := ExtractFilePath(ParamStr(0));
if OpenDialog1.Execute then
begin
if not FilterGraph1.Active then FilterGraph1.Active:= True;
VideoWindow1.FilterGraph:= FilterGraph1;
FilterGraph1.RenderFile(OpenDialog1.Filename);
FilterGraph1.Play;
end;
end;
procedure TForm21.Button2Click(Sender: TObject);
begin
FilterGraph1.Stop;
end;
procedure TForm21.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
FilterGraph1.ClearGraph;
FilterGraph1.Active:= False;
end;
end.
DFM
object Form21: TForm21
Left = 0
Top = 0
Caption = 'Form21'
ClientHeight = 441
ClientWidth = 644
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCloseQuery = FormCloseQuery
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 0
Top = 0
Width = 644
Height = 384
Align = alClient
Caption = 'Panel1'
TabOrder = 0
object VideoWindow1: TVideoWindow
Left = 1
Top = 1
Width = 642
Height = 382
Mode = vmVMR
FilterGraph = FilterGraph1
VMROptions.Mode = vmrWindowed
Color = clWhite
Align = alClient
end
end
object Panel2: TPanel
Left = 0
Top = 384
Width = 644
Height = 57
Align = alBottom
Caption = 'Panel2'
TabOrder = 1
object Button1: TButton
Left = 24
Top = 16
Width = 75
Height = 25
Caption = 'Play'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 128
Top = 16
Width = 75
Height = 25
Caption = 'Stop'
TabOrder = 1
OnClick = Button2Click
end
end
object FilterGraph1: TFilterGraph
GraphEdit = True
LinearVolume = True
Left = 424
Top = 144
end
object OpenDialog1: TOpenDialog
Left = 344
Top = 128
end
end
There is no built in support for seamless looping. Yes you certainly can receive completion event, seek playback to the beginning and run the graph again, however this would inevitably have a restart delay and possibly flickering.
To implement seamless looping you either a multigraph solution, to restart upstream graph while presentation graph is on a short pause and does not flicker. Or otherwise add custom filters into the pipeline to restart streaming internally and present it as continuous stream.
Summarization:
Please see the helpful comments below from Craig and Sertac.
======================================================
As shown in the following minimized code, TForm10 is set to be fsStayOnTop. TForm10.btnTryDlgClick call dlgOpen1.Execute, and the dialog shown is as expected. However, when I call TForm11.Create(Self).ShowModal inside TForm10.btnTryFormClick, the form is hidden behind the TForm10. I am wondering how to understand this behavior, and why standard TOpenDialog can show as expected? Any comment is appreciated!
PS: One workaround is to override the CreateParams procedure of TForm11, and set Params.wndParent to 0. But it looks to me that window hierarchy will be broke using this workaround.
procedure TForm11.CreateParams(var Params: TCreateParams); // override;
begin
inherited;
params.wndParent := 0;
end;
PS: Another workaround is mentioned by Remy in the below relevant SO pages: setting the modal Form's PopupParent property to be the StayOnTop Form. But in the followed comments, Sertac mentioned this workaround will also break window hierarchy.
PS: Possibly relevant SO pages:
Modal forms hidden by fsStayOnTop forms
How Can I Keep the FindDialog from Staying on Top (Delphi)?
How to make sure a dialog is always front of the main window
Form is hidden behind other forms when ShowModal is called
Make 2 forms able to overlap each other?
Multiple form Delphi applications and dialogs
Newly created modal window loses focus and become inacessible in Windows Vista
Delphi - How to prevent Forms/MsgBoxes to move under prior form?
How to allow Delphi secondary forms behind the main form
Fake modal dialog using Show?
Delphi MainFormOnTaskBar Modal windows bug
Source for Unit10:
unit Unit10;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm10 = class(TForm)
btnTryDlg: TButton;
dlgOpen1: TOpenDialog;
btnTryForm: TButton;
procedure FormCreate(Sender: TObject);
procedure btnTryDlgClick(Sender: TObject);
procedure btnTryFormClick(Sender: TObject);
end;
var
Form10: TForm10;
implementation
{$R *.dfm}
uses
Unit11;
procedure TForm10.FormCreate(Sender: TObject);
begin
FormStyle := fsStayOnTop;
end;
procedure TForm10.btnTryDlgClick(Sender: TObject);
begin
dlgOpen1.Execute;
// dlgOpen1.Execute(Self.Handle);
end;
procedure TForm10.btnTryFormClick(Sender: TObject);
begin
TForm11.Create(Self).ShowModal;
end;
end.
DFM for Unit10:
object Form10: TForm10
Left = 0
Top = 0
Caption = 'Form10'
ClientHeight = 255
ClientWidth = 414
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object btnTryDlg: TButton
Left = 32
Top = 24
Width = 153
Height = 201
Caption = 'Try dialog'
TabOrder = 0
OnClick = btnTryDlgClick
end
object btnTryForm: TButton
Left = 224
Top = 24
Width = 153
Height = 201
Caption = 'btnTryForm'
TabOrder = 1
OnClick = btnTryFormClick
end
object dlgOpen1: TOpenDialog
Left = 96
Top = 168
end
end
Source for Unit11:
unit Unit11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm11 = class(TForm)
end;
implementation
{$R *.dfm}
end.
DFM for Unit11:
object Form11: TForm11
Left = 0
Top = 0
Caption = 'Form11'
ClientHeight = 183
ClientWidth = 203
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
end
Set the modal form's PopupParent property, exactly like Remy suggested. That will parent the dialog to the StayOnTop form, which is what the dialog's Execute method is already doing. I'm not sure where Sertac's comments are coming from, but using PopupParent sets the window heirarchy correctly, so the dialog will always be above the StayOnTop form.
Summarization:
Please see Andreas' knowledgeable comments!
==========================================
As shown in the following code, TForm7 is the MDIForm form, TForm8 is the MDIChild form. TForm8 contains an alClient aligned panel, which further contains a TPaintBox. If the TForm8's panel's ParentBackground is set to False, I cannot trigger TForm8's paintbox's paint event from TForm7. I am wondering why would this happen, and how can I trigger TForm8's paintbox's paint event without exlicitly refering to it. Any suggestion is appreciated!
Note: If I call Self.Repaint withint TForm8, for example inside its Click event, TForm8's paintbox's paint event can be triggered. It cannot be triggered only when I call form8.repaint outside TForm8. I am wondering why would this happen?
Possibly relevant SO pages:
How to repaint a parent form while a modal form is active?
Unit that contains the MDIForm form.
unit Unit7;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm7 = class(TForm)
procedure FormShow(Sender: TObject);
procedure FormClick(Sender: TObject);
end;
var
Form7: TForm7;
implementation
{$R *.dfm}
uses
Unit8;
procedure TForm7.FormShow(Sender: TObject);
begin
TForm8.Create(Self);
end;
procedure TForm7.FormClick(Sender: TObject);
begin
TForm8(ActiveMDIChild).Repaint;
end;
end.
Dfm of the above Unit.
object Form7: TForm7
Left = 0
Top = 0
Caption = 'Form7'
ClientHeight = 379
ClientWidth = 750
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
FormStyle = fsMDIForm
OldCreateOrder = False
OnClick = FormClick
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
end
Unit that contains the MDIChild form.
unit Unit8;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TForm8 = class(TForm)
pb1: TPaintBox;
pnl1: TPanel;
procedure pb1Paint(Sender: TObject);
procedure pb1Click(Sender: TObject);
private
fCounter: Integer;
end;
implementation
{$R *.dfm}
procedure TForm8.pb1Click(Sender: TObject);
begin
Self.Repaint;
end;
procedure TForm8.pb1Paint(Sender: TObject);
begin
Self.pb1.Canvas.TextOut(30, 30, IntToStr(Self.fCounter));
Self.fCounter := Self.fCounter + 1;
end;
end.
Dfm of the above Unit.
object Form8: TForm8
Left = 0
Top = 0
Caption = 'Form8'
ClientHeight = 226
ClientWidth = 233
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
FormStyle = fsMDIChild
OldCreateOrder = False
Visible = True
PixelsPerInch = 96
TextHeight = 13
object pnl1: TPanel
Left = 0
Top = 0
Width = 233
Height = 226
Align = alClient
ShowCaption = False
TabOrder = 0
object pb1: TPaintBox
Left = 1
Top = 1
Width = 231
Height = 224
Align = alClient
OnClick = pb1Click
OnPaint = pb1Paint
ExplicitLeft = 56
ExplicitTop = -64
ExplicitWidth = 105
ExplicitHeight = 105
end
end
end
I think this is the case:
Believe it or not, the "normal" behaviour is that, if you repaint a form (or some other container), only that container gets repainted, not the children contained in it. However, with the advent of visual themes, controls got semi-transparent parts, and all of a sudden you need to repaint the child controls when the parent is redrawn, simply because the children need to reblend into the new background.
My hypothesis is (relatively) readily validated by scrutinizing the VCL source code, e.g.
procedure TWinControl.CMInvalidate(var Message: TMessage);
begin
{ Removed irrelevant code to avoid copyvio issues. }
InvalidateRect(WindowHandle, nil, not (csOpaque in ControlStyle));
{ Invalidate child windows which use the parentbackground when themed }
if ThemeServices.ThemesEnabled then
for I := 0 to ControlCount - 1 do
if csParentBackground in Controls[I].ControlStyle then
Controls[I].Invalidate;
{ Removed irrelevant code to avoid copyvio issues. }
end;
Therefore, when ParentBackground is set to false, and the panel bahaves like a classic panel, it isn't repainted when its parent is. On the other hand, if ParentBackground is true, it does get repainted along with its parent.
Hence there is no problem, really; you simply expect a behaviour that isn't to be expected.
So you need to repaint the paint box manually, by following David's advice.
You just need to call pb1.Invalidate when you want the paint box to re-draw itself.
Or am I misunderstanding your question?