PDA

View Full Version : رسم ماتریس



AliRezaBeytari
چهارشنبه 26 فروردین 1394, 20:47 عصر
سلام. چطور مثلا میشه این آرایه :


int[,] matrix = new int[3, 4] {
{0, -1, -2, -3},
{1, 0, -1, -2},
{2, 1, 0, -1}
};


رو به در یک pictureBox رسم کرد ؟؟!!!
مثلا اینطوری بشه :

130360

Mahmoud Zaad
چهارشنبه 26 فروردین 1394, 22:07 عصر
سلام
شما اول باید اندازه ارتفاع و عرض تصویر ماتریس (http://www.dotnetperls.com/2d-array) رو به دست بیاری.
برای ارتفاع باید ارتفاع فونتی که به کار می بری رو به دست بیاری بعد در تعداد سطرهای ماتریس ضرب کنی و البته به تعداد n-1 هم فضای سفید در نظر بگیری. یعنی توی مثال شما به فرض اگه از تاهوما 10 استفاده کنی، ارتفاعش میشه 17، حالا چون 3 تا سطر داریم n-1 = 2 تا هم فضای سفید داریم. که اینجوری ارتفاع ماتریس به دست میاد.

Font f = new Font("tahoma", 10, FontStyle.Regular);
MessageBox.Show(f.Height.ToString());


برای عرض باید همه آیتم های همه سطرها رو بخونید و اندازه آیتم های سطرها رو پیدا کنید و بیشترین مقدار رو به عنوان اندازه عرض قرار بدید. برای به دست آوردن اندازه یه آرایه از measurString استفاده میشه.
int itemWidth;
using (Graphics graphics = this.CreateGraphics())
{
itemWidth = (int)graphics.MeasureString(matrix[0, 0].ToString(), this.Font).Width;
}
MessageBox.Show(itemWidth.ToString());

برای براکت ها هم که از 3 تا خط استفاده میشه. خط بزرگه که یه مقدار بیشتر از ارتفاع هست که توضیح دادم، یه خط افقی بالاش داریم که نقطه شروع میشه شروع خط اول با اندازه مشخص، خط افقی پایین هم که شروعش پایان خط بزرگ هست با اندازه خط افقی بالایی...
حالا از یه نقطه ای شروع می کنید اول براکت سمت چپ رو رسم می کنید بعد با یه فاصله آرایه اول بعد فاصله و ... بعدش هم براکت سمت راست.

plus
چهارشنبه 26 فروردین 1394, 23:21 عصر
در ادامه توضیحات دوستمون، شما میتونی اون عملیات رو در یک UserControl به صورت زیر پیاده کنی:

130365


public partial class MatrixControl : UserControl {
private static readonly string emptyString = "(empty)";
private static readonly Padding elementMargin = new Padding(1);
private static readonly string separator = "=";

private int braceWidth;
private Rectangle closingBraceRect;
private Size elementSize;
private Rectangle openingBraceRect;
private string title;
private Rectangle titleRectangle;
private Array value = null;
private Rectangle valueRectangle;
public MatrixControl() {
InitializeComponent();
base.AutoSize = true;
base.AutoSizeMode = AutoSizeMode.GrowAndShrink;
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool AutoSize {
get {
return base.AutoSize;
}
set {
}
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]
public AutoSizeMode AutSizeMode {
get {
return base.AutoSizeMode;
}
set {

}
}
[Browsable(true)]
[DefaultValue(null)]
[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public string Title {
get {
return this.title;
}
set {
if (this.title != value) {
this.title = value;
this.OnTitleChanged(EventArgs.Empty);
}
}
}
public object Value {
get {
return this.value;
}
set {
if (!(value is Array) || ((Array)value).Rank != 2) {
throw new InvalidOperationException("Value must be a two-dimension array.");
}
if (this.value != value) {
this.value = (Array)value;
this.OnValueChanged(EventArgs.Empty);
}
}
}
private void DrawBraces(Graphics graphics, Rectangle clipRectangle) {
using (Pen bracePen = new Pen(this.ForeColor, (float)Math.Ceiling(this.braceWidth / 4.0f))) {
int halfPenWidth = (int)Math.Ceiling(bracePen.Width / 2);
if (clipRectangle.IntersectsWith(this.openingBraceRec t)) {
using (GraphicsPath path = new GraphicsPath()) {
path.AddLines(new Point[] {
new Point(this.openingBraceRect.Right, this.openingBraceRect.Top + halfPenWidth),
new Point(this.openingBraceRect.Left + halfPenWidth, this.openingBraceRect.Top + halfPenWidth),
new Point(this.openingBraceRect.Left + halfPenWidth, this.openingBraceRect.Bottom - halfPenWidth),
new Point(this.openingBraceRect.Right, this.openingBraceRect.Bottom - halfPenWidth),
});
graphics.DrawPath(bracePen, path);
}
}
if (clipRectangle.IntersectsWith(this.closingBraceRec t)) {
using (GraphicsPath path = new GraphicsPath()) {
path.AddLines(new Point[] {
new Point(this.closingBraceRect.Left, this.closingBraceRect.Top + halfPenWidth),
new Point(this.closingBraceRect.Right - halfPenWidth, this.closingBraceRect.Top + halfPenWidth),
new Point(this.closingBraceRect.Right - halfPenWidth, this.closingBraceRect.Bottom - halfPenWidth),
new Point(this.closingBraceRect.Left, this.closingBraceRect.Bottom - halfPenWidth)
});
graphics.DrawPath(bracePen, path);
}
}
}
}
private void DrawElement(Graphics graphics, Rectangle clipRectangle, int i, int j, int collb, int rowlb) {
object element = this.value.GetValue(i, j);
if (element != null) {
Rectangle elementRect = new Rectangle(valueRectangle.Location, this.elementSize);
elementRect.Offset(this.braceWidth, 0);
elementRect.Offset((j - collb) * elementSize.Width, (i - rowlb) * elementSize.Height);
if (clipRectangle.IntersectsWith(elementRect)) {
TextRenderer.DrawText(graphics,
element.ToString(),
this.Font,
elementRect,
this.ForeColor,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);

}
}
}
public override Size GetPreferredSize(Size proposedSize) {
return new Size(this.titleRectangle.Width + this.valueRectangle.Width, this.valueRectangle.Height);
}
private void MeasureBounds() {
this.MeasureTitleBounds();
this.MeasureValueBounds();
}
private void MeasureTitleBounds() {
int fontHeight = this.Font.Height;
Size titleSize;

if (!string.IsNullOrEmpty(this.title)) {
string titleAndSeparator = string.Format("{0} {1} ", this.title, separator);
titleSize = TextRenderer.MeasureText(titleAndSeparator, this.Font);
}
else {
titleSize = Size.Empty;
}
Point titleLocation = new Point();
titleLocation.Y = (this.ClientRectangle.Height - titleSize.Height) / 2;
this.titleRectangle = new Rectangle(titleLocation, titleSize);
}
private void MeasureValueBounds() {
int fontHeight = this.Font.Height;
Size valueSize;

if (this.value == null) {
valueSize = TextRenderer.MeasureText(emptyString, this.Font);
this.braceWidth = 0;
this.closingBraceRect = Rectangle.Empty;
this.elementSize = Size.Empty;
this.openingBraceRect = Rectangle.Empty;
}
else {
this.braceWidth = TextRenderer.MeasureText("0", this.Font).Width / 2;

int rowlb = this.value.GetLowerBound(0);
int rowhb = this.value.GetUpperBound(0);
int collb = this.value.GetLowerBound(1);
int colhb = this.value.GetUpperBound(1);
int rows = rowhb - rowlb + 1;
int cols = colhb - collb + 1;
int valueHeight = rows * (fontHeight + elementMargin.Vertical);

int maxElementWidth = 0;
for (int j = collb; j <= colhb; j++) {
for (int i = rowlb; i <= rowhb; i++) {
Size elementSize = Size.Empty;
object element = this.value.GetValue(i, j);
if (element != null) {
elementSize = TextRenderer.MeasureText(element.ToString(), this.Font);
}
maxElementWidth = Math.Max(maxElementWidth, elementSize.Width);
}
}
this.elementSize = new Size(maxElementWidth + elementMargin.Horizontal, fontHeight + elementMargin.Vertical);

int valueWidth = cols * (maxElementWidth + elementMargin.Horizontal) + 2 * this.braceWidth;
valueSize = new Size(valueWidth, valueHeight);
}
Point valueLocation = new Point();
valueLocation.X = this.titleRectangle.Right;
this.valueRectangle = new Rectangle(valueLocation, valueSize);

this.closingBraceRect = new Rectangle(valueRectangle.Right - this.braceWidth, 0, this.braceWidth, valueSize.Height);
this.openingBraceRect = new Rectangle(valueRectangle.Left, 0, this.braceWidth, valueSize.Height);
}
protected override void OnPaintBackground(PaintEventArgs e) {
base.OnPaintBackground(e);
if (e.ClipRectangle.IntersectsWith(this.titleRectangl e)) {
if (!string.IsNullOrEmpty(this.title)) {
string titleAndSeparator = string.Format("{0} {1} ", this.title, separator);
TextRenderer.DrawText(e.Graphics, titleAndSeparator, this.Font, this.titleRectangle, this.ForeColor);
}
}
Rectangle clipRectangle = e.ClipRectangle;
if (clipRectangle.IntersectsWith(this.valueRectangle) ) {
if (this.value != null) {
int rowlb = this.value.GetLowerBound(0);
int rowhb = this.value.GetUpperBound(0);
int collb = this.value.GetLowerBound(1);
int colhb = this.value.GetUpperBound(1);
for (int j = collb; j <= colhb; j++) {
for (int i = rowlb; i <= rowhb; i++) {
this.DrawElement(e.Graphics, e.ClipRectangle, i, j, collb, rowlb);
}
}
this.DrawBraces(e.Graphics, e.ClipRectangle);
}
else {
TextRenderer.DrawText(e.Graphics, emptyString, this.Font, this.valueRectangle, this.ForeColor);
}
}
}
protected override void OnFontChanged(EventArgs e) {
this.MeasureBounds();
base.PerformLayout(this, "PreferredSize");
base.OnFontChanged(e);
}
protected override void OnSizeChanged(EventArgs e) {
this.MeasureBounds();
this.Invalidate();
base.OnSizeChanged(e);
}
private void OnTitleChanged(EventArgs e) {
this.MeasureBounds();
this.PerformLayout(this, "PreferredSize");
this.Invalidate();
}
private void OnValueChanged(EventArgs e) {
this.MeasureValueBounds();
this.PerformLayout(this, "PreferredSize");
this.Invalidate();
}
}

در این حالت میتونی یک شی ازین کنترل در فرم ایجاد کنی و ماتریس مورد نظر رو به مشخصه Value اون اختصاص بدی.
ظرف مدت کوتاهی نوشتمش و ممکنه امکاناتی بخواین که نداشته باشه یا ظاهر بهتری بخواین که میتوننید خودتون دست به کار بشین و ویرایشش کنید.

AliRezaBeytari
پنج شنبه 27 فروردین 1394, 07:55 صبح
از هر دو شما عزیزان خیلی خیلی ممنونم ؛ مخصوصا شما جناب plus.
فقط اگر میشه بگید چطور باید Value رو مقدار دهی کنم ؟؟!!
من اینطوری میخواستم عمل کنم که نشد !!!!


int[,] matrix = new int[3, 4] {
{0, -1, -2, -3},
{1, 0, -1, -2},
{2, 1, 0, -1}
};
matrixControl1.Value = matrix;

plus
پنج شنبه 27 فروردین 1394, 16:52 عصر
باید همینطوری مقدار دهی کنی. مقدار دهی رو بعد از InitializeComponent انجام میدین؟
برای مثال از طریق کد من اینطوری یک شی ازش ایجاد میکنم:

MatrixControl matrixControl;
public Form1() {
InitializeComponent();

int[,] matrix = new int[3, 4] {
{0, -1, -2, -3},
{1, 0, -1, -2},
{2, 1, 0, -1}
};

matrixControl = new MatrixControl();
matrixControl.BackColor = Color.White;
matrixControl.Font = new Font("Tahoma", 20.0f);
matrixControl.Left = 40;
matrixControl.Top = 50;
matrixControl.Title = "A";
matrixControl.Value = matrix;
this.Controls.Add(matrixControl);
}

البته از طریق Designer هم نباید مشکلی باشه...

AliRezaBeytari
جمعه 28 فروردین 1394, 14:50 عصر
خیلی ممنونم ، کار کرد.
فقط من یه مشکلی دیگه هم دارم که خیلی ممنون میشم اگر کمکم کنید.

من توی برنامم ، از کاربر تعداد سطرها و ستون ها رو دریافت میکنم و بعد از اینکه کاربر بر روی دکمه OK کلیک کرد ، اون تعداد سطرها و ستون ها رو ارجاع میدم به یه فرم دیگه.
من در اون فرم جدید میخوام مثل یک ماتریس به تعداد (سطرها * ستون ها ) یا (n*m) کنترل TextBox داشته باشم که همشون با نظم خوبی درون دوتا کروشه قرار دارند.
درحقیقت به جای اینکه بخوام در درایه های ماتریس ، عدد نشون بدم ، میخوام TextBox برای وارد کردن داده درست کنم.
اگر میشه راهنمایی کنید چطور میتونم اینکار رو کنم ؟؟؟!!

plus
جمعه 28 فروردین 1394, 19:49 عصر
یک راه حل این هست که شما از کنترل DataGridView استفاده کنی و مشخصات رو جوری تنظیم کنی که شبیه ماتریس به نظر بیاد و با گذاشتن تصویر اطراف اون براکتها رو شبیه سازی کنی.
راه حل دیگه این هست که با استفاده از حلقه، شی TextBox به تعداد مورد نیاز درست کنی و با تنظیم مشخه های Location و Width، ماتریس رو ایجاد کنی.

راه حل زیبا تر، دقیق تر و البته سخت تر بست دادن کنترلی هست که براتون نوشتم به صورتی که بتونه ورودی بگیره هست.

hoseinharami
جمعه 28 فروردین 1394, 20:28 عصر
یک راه حل این هست که شما از کنترل DataGridView استفاده کنی و مشخصات رو جوری تنظیم کنی که شبیه ماتریس به نظر بیاد و با گذاشتن تصویر اطراف اون براکتها رو شبیه سازی کنی.
راه حل دیگه این هست که با استفاده از حلقه، شی TextBox به تعداد مورد نیاز درست کنی و با تنظیم مشخه های Location و Width، ماتریس رو ایجاد کنی.

راه حل زیبا تر، دقیق تر و البته سخت تر بست دادن کنترلی هست که براتون نوشتم به صورتی که بتونه ورودی بگیره هست.

سلام
میشه توضیح بدین بست دادن کنترلی یعنی چی؟

AliRezaBeytari
جمعه 28 فروردین 1394, 21:24 عصر
راه حل اول رو امتحان کردم ، اصلا خوب نمیشه !!
راه حل دوم رو هم قبلا امتحان کرده بودم ، اما نتونستم Location درست هر TextBox رو پیدا کنم و به مشکل بر خوردم !!
راه حل سوم رو هم متوجه نشدم !!!

plus
جمعه 28 فروردین 1394, 22:18 عصر
منظورم این هست که کنترلی که نوشتم رو کاملتر کنید گه البته اگه راه دوم رو نتونید انجام بدین از عهده سومی هم بر نمیایین. به نظرم روی دومی بیشتر کار کنید.