分享
 
 
 

关于对微软MSDN扩展图片弹出对话框的改进(可以正常比例显示图片缩略图)

王朝other·作者佚名  2006-05-14
窄屏简体版  字體: |||超大  

首先从这里下载:Download the ExtensibleDialogsSource.msi sample file (297 KB).

原文链接:Extend the Common Dialog Boxes Using Windows Forms 1.x

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwinforms/html/extensibledialogs.asp

下载后安装,然后打开项目文件,将OpenFileDialog.cs文件中的内容替换如下:

/*================================================================================

File: OpenFileDialog.cs

Summary: This is part of a sample showing how to place Windows Forms controls

inside one of the common file dialogs.

----------------------------------------------------------------------------------

Copyright (C) Microsoft Corporation. All rights reserved.

This source code is intended only as a supplement to Microsoft Development Tools

and/or on-line documentation. See these other materials for detailed information

regarding Microsoft code samples.

This sample is not intended for production use. Code and policy for a production

application must be developed to meet the specific data and security requirements

of the application.

THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,

EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES

OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

================================================================================*/

using System;

using System.Text;

using System.Runtime.InteropServices;

using System.Drawing;

namespace ExtensibleDialogs

{

/// <summary>

/// The extensible OpenFileDialog

/// </summary>

public class OpenFileDialog : IDisposable

{

// The maximum number of characters permitted in a path

private const int _MAX_PATH = 260;

// The "control ID" of the content window inside the OpenFileDialog

// See the accompanying article to learn how I discovered it

private const int _CONTENT_PANEL_ID = 0x0461;

// A constant that determines the spacing between panels inside the OpenFileDialog

private const int _PANEL_GAP_FACTOR = 3;

/// <summary>

/// Clients can implement handlers of this type to catch "selection changed" events

/// </summary>

public delegate void SelectionChangedHandler( string path );

/// <summary>

/// This event is fired whenever the user selects an item in the dialog

/// </summary>

public event SelectionChangedHandler SelectionChanged;

// unmanaged memory buffers to hold the file name (with and without full path)

private IntPtr _fileNameBuffer;

private IntPtr _fileTitleBuffer;

// the OPENFILENAME structure, used to control the appearance and behaviour of the OpenFileDialog

private OpenFileName _ofn;

// user-supplied control that gets placed inside the OpenFileDialog

private System.Windows.Forms.Control _userControl;

// unmanaged memory buffer that holds the Win32 dialog template

private IntPtr _ipTemplate;

/// <summary>

/// Sets up the data structures necessary to display the OpenFileDialog

/// </summary>

/// <param name="defaultExtension">The file extension to use if the user doesn't specify one (no "." required)</param>

/// <param name="fileName">You can specify a filename to appear in the dialog, although the user can change it</param>

/// <param name="filter">See the documentation for the OPENFILENAME structure for a description of filter strings</param>

/// <param name="userPanel">Any Windows Forms control, it will be placed inside the OpenFileDialog</param>

public OpenFileDialog( string defaultExtension, string fileName, string filter, System.Windows.Forms.Control userControl )

{

// Need two buffers in unmanaged memory to hold the filename

// Note: the multiplication by 2 is to allow for Unicode (16-bit) characters

_fileNameBuffer = Marshal.AllocCoTaskMem( 2 * _MAX_PATH );

_fileTitleBuffer = Marshal.AllocCoTaskMem( 2 * _MAX_PATH );

// Zero these two buffers

byte[] zeroBuffer = new byte [2 * (_MAX_PATH+1)];

for( int i = 0; i < 2 * (_MAX_PATH+1); i++ ) zeroBuffer[i] = 0;

Marshal.Copy( zeroBuffer, 0, _fileNameBuffer, 2 * _MAX_PATH );

Marshal.Copy( zeroBuffer, 0, _fileTitleBuffer, 2 * _MAX_PATH );

// Create an in-memory Win32 dialog template; this will be a "child" window inside the FileOpenDialog

// We have no use for this child window, except that its presence allows us to capture events when

// the user interacts with the FileOpenDialog

_ipTemplate = BuildDialogTemplate();

// Populate the OPENFILENAME structure

// The flags specified are the minimal set to get the appearance and behaviour we need

_ofn.lStructSize = Marshal.SizeOf( _ofn );

_ofn.lpstrFile = _fileNameBuffer;

_ofn.nMaxFile = _MAX_PATH;

_ofn.lpstrDefExt = Marshal.StringToCoTaskMemUni( defaultExtension );

_ofn.lpstrFileTitle = _fileTitleBuffer;

_ofn.nMaxFileTitle = _MAX_PATH;

_ofn.lpstrFilter = Marshal.StringToCoTaskMemUni( filter );

_ofn.Flags = OpenFileNameFlags.EnableHook | OpenFileNameFlags.EnableTemplateHandle | OpenFileNameFlags.EnableSizing | OpenFileNameFlags.Explorer;

_ofn.hInstance = _ipTemplate;

_ofn.lpfnHook = new OfnHookProc(MyHookProc);

// copy initial file name into unmanaged memory buffer

UnicodeEncoding ue = new UnicodeEncoding();

byte[] fileNameBytes = ue.GetBytes( fileName );

Marshal.Copy( fileNameBytes, 0, _fileNameBuffer, fileNameBytes.Length );

// keep a reference to the user-supplied control

_userControl = userControl;

}

/// <summary>

/// The finalizer will release the unmanaged memory, if I should forget to call Dispose

/// </summary>

~OpenFileDialog()

{

Dispose( false );

}

/// <summary>

/// Display the OpenFileDialog and allow user interaction

/// </summary>

/// <returns>true if the user clicked OK, false if they clicked cancel (or close)</returns>

public bool Show()

{

return NativeMethods.GetOpenFileName( ref _ofn );

}

/// <summary>

/// Builds an in-memory Win32 dialog template. See documentation for DLGTEMPLATE.

/// </summary>

/// <returns>a pointer to an unmanaged memory buffer containing the dialog template</returns>

private IntPtr BuildDialogTemplate()

{

// We must place this child window inside the standard FileOpenDialog in order to get any

// notifications sent to our hook procedure. Also, this child window must contain at least

// one control. We make no direct use of the child window, or its control.

// Set up the contents of the DLGTEMPLATE

DlgTemplate template = new DlgTemplate();

// Allocate some unmanaged memory for the template structure, and copy it in

IntPtr ipTemplate = Marshal.AllocCoTaskMem( Marshal.SizeOf(template) );

Marshal.StructureToPtr( template, ipTemplate, true );

return ipTemplate;

}

/// <summary>

/// The hook procedure for window messages generated by the FileOpenDialog

/// </summary>

/// <param name="hWnd">the handle of the window at which this message is targeted</param>

/// <param name="msg">the message identifier</param>

/// <param name="wParam">message-specific parameter data</param>

/// <param name="lParam">mess-specific parameter data</param>

/// <returns></returns>

public IntPtr MyHookProc( IntPtr hWnd, UInt16 msg, Int32 wParam, Int32 lParam )

{

if (hWnd == IntPtr.Zero)

return IntPtr.Zero;

// Behaviour is dependant on the message received

switch( msg )

{

// We're not interested in every possible message; just return a NULL for those we don't care about

default:

{

return IntPtr.Zero;

}

// WM_INITDIALOG - at this point the OpenFileDialog exists, so we pull the user-supplied control

// into the FileOpenDialog now, using the SetParent API.

case WindowMessage.InitDialog:

{

IntPtr hWndParent = NativeMethods.GetParent( hWnd );

NativeMethods.SetParent( _userControl.Handle, hWndParent );

return IntPtr.Zero;

}

// WM_SIZE - the OpenFileDialog has been resized, so we'll resize the content and user-supplied

// panel to fit nicely

case WindowMessage.Size:

{

FindAndResizePanels( hWnd );

return IntPtr.Zero;

}

// WM_NOTIFY - we're only interested in the CDN_SELCHANGE notification message:

// we grab the currently-selected filename and fire our event

case WindowMessage.Notify:

{

IntPtr ipNotify = new IntPtr( lParam );

OfNotify ofNot = (OfNotify)Marshal.PtrToStructure( ipNotify, typeof(OfNotify) );

UInt16 code = ofNot.hdr.code;

if( code == CommonDlgNotification.SelChange )

{

// This is the first time we can rely on the presence of the content panel

// Resize the content and user-supplied panels to fit nicely

FindAndResizePanels( hWnd );

// get the newly-selected path

IntPtr hWndParent = NativeMethods.GetParent( hWnd );

StringBuilder pathBuffer = new StringBuilder(_MAX_PATH);

UInt32 ret = NativeMethods.SendMessage( hWndParent, CommonDlgMessage.GetFilePath, _MAX_PATH, pathBuffer );

string path = pathBuffer.ToString();

// copy the string into the path buffer

UnicodeEncoding ue = new UnicodeEncoding();

byte[] pathBytes = ue.GetBytes( path );

Marshal.Copy( pathBytes, 0, _fileNameBuffer, pathBytes.Length );

// fire selection-changed event

if( SelectionChanged != null ) SelectionChanged( path );

}

return IntPtr.Zero;

}

}

}

/// <summary>

/// Layout the content of the OpenFileDialog, according to the overall size of the dialog

/// </summary>

/// <param name="hWnd">handle of window that received the WM_SIZE message</param>

private void FindAndResizePanels( IntPtr hWnd )

{

// The FileOpenDialog is actually of the parent of the specified window

IntPtr hWndParent = NativeMethods.GetParent( hWnd );

// The "content" window is the one that displays the filenames, tiles, etc.

// The _CONTENT_PANEL_ID is a magic number - see the accompanying text to learn

// how I discovered it.

IntPtr hWndContent = NativeMethods.GetDlgItem( hWndParent, _CONTENT_PANEL_ID );

Rectangle rcClient = new Rectangle( 0, 0, 0, 0 );

Rectangle rcContent = new Rectangle( 0, 0, 0, 0 );

// Get client rectangle of dialog

RECT rcTemp = new RECT();

NativeMethods.GetClientRect( hWndParent, ref rcTemp );

rcClient.X = rcTemp.left;

rcClient.Y = rcTemp.top;

rcClient.Width = rcTemp.right - rcTemp.left;

rcClient.Height = rcTemp.bottom - rcTemp.top;

// The content window may not be present when the dialog first appears

if( hWndContent != IntPtr.Zero )

{

// Find the dimensions of the content panel

RECT rc = new RECT();

NativeMethods.GetWindowRect( hWndContent, ref rc );

// Translate these dimensions into the dialog's coordinate system

POINT topLeft;

topLeft.X = rc.left;

topLeft.Y = rc.top;

NativeMethods.ScreenToClient( hWndParent, ref topLeft );

POINT bottomRight;

bottomRight.X = rc.right;

bottomRight.Y = rc.bottom;

NativeMethods.ScreenToClient( hWndParent, ref bottomRight );

rcContent.X = topLeft.X;

rcContent.Width = bottomRight.X - topLeft.X;

rcContent.Y = topLeft.Y;

rcContent.Height = bottomRight.Y - topLeft.Y;

// Shrink content panel's width

int width = rcClient.Right - rcContent.Left;

rcContent.Width = (int)(width * 1.0 /1.6) + _PANEL_GAP_FACTOR;

NativeMethods.MoveWindow( hWndContent, rcContent.Left, rcContent.Top, rcContent.Width, rcContent.Height, true );

}

// Position the user-supplied control alongside the content panel

Rectangle rcUser = new Rectangle( rcContent.Right + (2 * _PANEL_GAP_FACTOR), rcContent.Top, rcClient.Right - rcContent.Right - (3 * _PANEL_GAP_FACTOR), rcContent.Bottom - rcContent.Top );

NativeMethods.MoveWindow( _userControl.Handle, rcUser.X, rcUser.Y, rcUser.Width, rcUser.Height, true );

}

/// <summary>

/// returns the path currently selected by the user inside the OpenFileDialog

/// </summary>

public string SelectedPath

{

get

{

return Marshal.PtrToStringUni( _fileNameBuffer );

}

}

#region IDisposable Members

public void Dispose()

{

Dispose( true );

}

/// <summary>

/// Free any unamanged memory used by this instance of OpenFileDialog

/// </summary>

/// <param name="disposing">true if called by Dispose, false otherwise</param>

public void Dispose( bool disposing )

{

if( disposing )

{

GC.SuppressFinalize( this );

}

Marshal.FreeCoTaskMem( _fileNameBuffer );

Marshal.FreeCoTaskMem( _fileTitleBuffer );

Marshal.FreeCoTaskMem( _ipTemplate );

}

#endregion

}

}

MainForm.cs中修改一下:

private void button1_Click(object sender, System.EventArgs e)事件和private void ofd_SelectionChanged( string path ),代码如下:

/// <summary>

/// Creates and shows an instance of the extended OpenFileDialog, with a PictureBox control placed inside

/// </summary>

private void button1_Click(object sender, System.EventArgs e)

{

// Create panel for the "preview" part of the dialog

Panel p = new Panel();

p.BorderStyle = BorderStyle.None;

// Add a picture box to the "preview" panel

_picBox = new PictureBox();

p.Controls.Add( _picBox );

_picBox.Dock = DockStyle.Fill;

_picBox.SizeMode = PictureBoxSizeMode.StretchImage;

_picBox.Click += new EventHandler( picBox_Click );

// Create and show the OpenFile Dialog

ExtensibleDialogs.OpenFileDialog ofd = new ExtensibleDialogs.OpenFileDialog( "jpg", "", "Picture files (*.JPG;*.GIF;*.PNG;*.tif)\0*.jpg;*.gif;*.png;*.tif\0\0", p );

ofd.SelectionChanged += new ExtensibleDialogs.OpenFileDialog.SelectionChangedHandler(ofd_SelectionChanged);

bool f = ofd.Show();

string s = ofd.SelectedPath;

if(s != string.Empty)

{

MessageBox.Show("You selected a photo, the file name is:\n" + s);

}

}

/// <summary>

/// Event handler that is called when the user clicks on a file or folder inside the dialog

/// </summary>

/// <param name="path">the full path of the currently-selected file</param>

private void ofd_SelectionChanged( string path )

{

// Check the path points to something valid before trying to display the contents

if( !File.Exists( path ) ) return;

if( !Path.HasExtension( path ) ) return;

string ext = Path.GetExtension( path ).ToLower();

if( ext == ".jpg" || ext == ".gif" || ext == ".png" || ext == ".tif" )

{

Image originalImage = new Bitmap(path);

int widthOriginal = originalImage.Width;

int heightOriginal = originalImage.Height;

int boxW = _picBox.Width;

int boxH = _picBox.Height;

Bitmap newBmp = new Bitmap(boxW, boxH);

Graphics g = Graphics.FromImage(newBmp);

float zoom = Math.Min((float)boxW / (originalImage.Width + 1), (float) boxH / (originalImage.Height + 1));

Rectangle destRect = new Rectangle(

(boxW - (int)(originalImage.Width * zoom))/2, (boxH - (int)(originalImage.Height * zoom))/2,

(int)(originalImage.Width * zoom), (int)(originalImage.Height * zoom));

Rectangle srcRect = new Rectangle(0, 0, originalImage.Width, originalImage.Height);

g.DrawImage(originalImage, destRect, srcRect, GraphicsUnit.Pixel);

_picBox.Image = newBmp;

g.Dispose();

originalImage.Dispose();

}

}

运行它,是不是比以前更方便和漂亮了点?

运行时截图:

主要的改进是修正了:

1、MSDN上的示例运行时图形区域太大,文件选择区域太小的问题。

2、修改了图像显示缩略图不成比例的问题。

美中不足:

(1)当选择好图片之后,如果点击“取消”,仍会弹出已选择的文件名。BUG!

(2)由于本人对C++不熟悉,无法调整弹出对话框的默认大小,目前好象只有560*340左右大小,哪位知道如何调整默认对话框尺寸,烦请告知为谢。

MSN:a3news#hotmail.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有