Teks ComboBox Sejajarkan Secara Vertikal di Tengah

Saya membuat kotak kombo khusus di .net framework 1.1, saya dapat menggambar item tarik-turun secara khusus, tetapi saya tidak dapat mengatur atau menggambar teks kotak kombo di Kiri Tengah, teks kotak kombo selalu ditampilkan di kiri atas, tetapi saya memerlukan teks harus dirender di kiri tengah .

[ToolboxBitmap(typeof(ComboBox))]
public class MenComboBox :ComboBox
{
    private Image _image = Image.FromFile("Expand.png");
    public MenComboBox()
    {
        this.DrawMode = DrawMode.OwnerDrawFixed;
        this.BackColor = Color.White;
        this.ItemHeight = 18;
        this.Font = new Font("Arial",12f,FontStyle.Regular);
    }       
    protected override void OnDrawItem(DrawItemEventArgs e)
    {

            if (!DesignMode)
            {
                if (e.Index > -1)
                {
                    int textHeight = (int)e.Graphics.MeasureString(this.Items[e.Index].ToString(), e.Font).Height;
                    Point textPos = new Point(e.Bounds.X + 4, e.Bounds.Y + ((this.ItemHeight - textHeight) / 2));
                    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                    {
                        e.Graphics.FillRectangle(Brushes.Blue, e.Bounds);
                        e.Graphics.DrawString(this.Items[e.Index].ToString(),e.Font,Brushes.White,textPos);
                    }
                    else
                    {
                        e.Graphics.FillRectangle(Brushes.White, e.Bounds);
                        e.Graphics.DrawString(this.Items[e.Index].ToString(),e.Font,Brushes.Black,textPos);
                    }
                }
            }

    }
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == 0x000F)
        {
            using (Graphics g = this.CreateGraphics())
            {
                g.FillRectangle(new SolidBrush(BackColor), this.ClientRectangle);
                g.DrawRectangle(Pens.Blue, new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1));
                Rectangle rect = new Rectangle(this.Width - 15, 3, 12, this.Height - 6);
                g.FillRectangle(new SolidBrush(BackColor), rect);
                g.DrawImage(this._image, this.Width - 16, (this.Height - 8) / 2);
                g.Dispose();
            }
        }
    }   
}

Penampilan Kotak Kombo Khusus saya


person Vignesh Nethaji    schedule 13.04.2018    source sumber
comment
Hapus coba/tangkap dan tunjukkan apa kesalahannya? Dan perhatikan bahwa menangkap semua pengecualian tidak masuk akal dan merupakan tanda kuat bahwa Anda melakukan kesalahan   -  person Evgeny Gorbovoy    schedule 13.04.2018
comment
Bagian kotak teks tidak memiliki opsi untuk menyelaraskan teks ke tengah, gambar khusus juga tidak memperbaikinya. Mengisi teks dengan spasi bisa menjadi solusi yang agak konyol. Ya, pengguna sudah terbiasa dengan tampilan+nuansa kotak kombo.   -  person Hans Passant    schedule 13.04.2018


Jawaban (2)


Dalam gambar pemilik ComboBox, teks bagian Edit kontrol akan selalu ditampilkan di kiri atas, berapa pun tinggi ItemHeight.

Untuk memposisikan bagian Edit secara vertikal di tengah, Anda dapat menemukan elemen Edit menggunakan GetComboBoxInfo dan kemudian menggunakan SetWindowPos atur posisi baru agar elemen tersebut berdiri vertikal di tengah ComboBox.

Anda perlu mengubah posisinya ketika ukuran kontrol berubah. Anda juga perlu mengisi latar belakang ComboBox dengan Warna.

masukkan deskripsi gambar di sini

Berikut kode yang saya gunakan:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyComboBox : ComboBox
{
    public MyComboBox()
    {
        SetStyle(ControlStyles.ResizeRedraw, true);
        DrawMode = DrawMode.OwnerDrawFixed;
        ItemHeight = 40;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
        public int Width { get { return Right - Left; } }
        public int Height { get { return Bottom - Top; } }
    }

    private const int SWP_NOSIZE = 0x0001;
    private const int SWP_NOZORDER = 0x0004;
    private const int SWP_SHOWWINDOW = 0x0040;
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, 
        int X, int Y, int cx, int cy, int uFlags);

    [DllImport("user32.dll")]
    public static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);

    [StructLayout(LayoutKind.Sequential)]
    public struct COMBOBOXINFO
    {
        public int cbSize;
        public RECT rcItem;
        public RECT rcButton;
        public int stateButton;
        public IntPtr hwndCombo;
        public IntPtr hwndEdit;
        public IntPtr hwndList;
    }
    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        SetupEdit();
        Invalidate();
    }
    private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0xF)
        {
            using (var g = this.CreateGraphics())
            {
                var r = new Rectangle(2, 2,
                    ClientRectangle.Width - buttonWidth - 2,
                    ClientRectangle.Height - 4);
                g.FillRectangle(Brushes.White, r);
            }
        }
        base.WndProc(ref m);
    }
    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);
        SetupEdit();
    }
    private void SetupEdit()
    {
        var info = new COMBOBOXINFO();
        info.cbSize = Marshal.SizeOf(info);
        GetComboBoxInfo(this.Handle, ref info);
        SetWindowPos(info.hwndEdit, IntPtr.Zero, 3,
            (this.Height - Font.Height) / 2,
            ClientRectangle.Width - buttonWidth - 3,
            ClientRectangle.Height - Font.Height - 4,
            SWP_NOZORDER);
    }
    protected override void OnDrawItem(DrawItemEventArgs e)
    {
        base.OnDrawItem(e);
        e.DrawBackground();
        var txt = "";
        if (e.Index >= 0)
            txt = GetItemText(Items[e.Index]);
        TextRenderer.DrawText(e.Graphics, txt, Font, e.Bounds, 
            ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
    }
}

masukkan deskripsi gambar di sini

person Reza Aghaei    schedule 13.04.2018
comment
Tapi apakah itu benar-benar menampilkan teks yang terpusat dan dapat diedit? - person TaW; 13.04.2018
comment
@TaW Ya, agar tidak terlalu membingungkan, saya mengubah tangkapan layarnya. Sebenarnya saya mengubah posisi kontrol Edit. Aku tidak melukisnya. - person Reza Aghaei; 13.04.2018
comment
Hm, aku bingung. Terutama ketika saya bertanya-tanya bagaimana OP bisa membuat teks muncul di kiri atas; tentu saja hal itu tidak berlaku di sini. Mungkin hal .Net .1.1..? - person TaW; 13.04.2018
comment
@TaW Ubah DrawMode menjadi OwnerDrawFixed dan atur ItemHeight menjadi 40 misalnya, maka Anda akan melihat bagian edit akan selalu muncul di kiri atas. - person Reza Aghaei; 13.04.2018
comment
Ah, ya, dengan kehati-hatian yang cukup, seseorang memang bisa menembak kakinya sendiri. Tinggi item tidak boleh disetel karena mengganggu ukuran Font. Setelah setting saya harus buka kode desgner untuk menghilangkannya lagi.. (Btw: Apakah itu perlu atau ada trik untuk meresetnya ke otomatis?) - person TaW; 13.04.2018
comment
@TaW Bayangkan kotak kombo gambar pemilik seperti ini. Dalam hal ini, tinggi Item harus diatur ke nilai yang lebih besar daripada tinggi font. - person Reza Aghaei; 13.04.2018
comment
Ya, itu adalah contoh yang bagus. Otoh, ketika pengguna dapat memperbesar font, menjaganya tetap otomatis jauh lebih sederhana.. Dan semua gambar pemilik hanyalah tentang perataan vertikal. Hehe, kita mungkin kehilangan dia ;-) - person TaW; 13.04.2018
comment
@Reza, ketika saya mengatur ukuran Arial 18f, maka teks Combobox tidak muncul dengan benar. ibb.co/kCR4p7 - person Vignesh Nethaji; 14.04.2018
comment
Menggunakan ItemHeight yang lebih besar memecahkan masalah saya. - person Reza Aghaei; 14.04.2018
comment
@reza Tetapi jika menambah tinggi item maka kontrolnya sangat besar, maka tampilannya tidak bagus, sehingga saya memerlukan teks juga harus menempati ruang margin. - person Vignesh Nethaji; 14.04.2018
comment
Saya tidak yakin apakah ada perbaikan lain untuk itu, Jika saya dapat menemukannya, saya akan memberi tahu Anda :) - person Reza Aghaei; 14.04.2018

oke, kode di bawah ini tidak menjawab pertanyaan sebenarnya tentang bagian Teks; Hans melakukannya dengan benar, seperti biasa.

Saya menyimpan jawabannya karena menurut saya ini melakukan beberapa hal lebih baik daripada kode OP..

masukkan deskripsi gambar di sini

    if (!DesignMode)
    {
        if (e.Index > -1)
        {
           using (StringFormat fmt = new StringFormat() 
             { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center })
           {

            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                e.Graphics.FillRectangle(SystemBrushes.MenuHighlight, e.Bounds);
                e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), 
                                        e.Font,SystemBrushes.HighlightText, e.Bounds, fmt);
            }
            else
            {
                e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
                e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), 
                                        e.Font, SystemBrushes.MenuText,e.Bounds, fmt);
            }
         }
      }
    }

Daripada menghitung posisi terpusat, saya menggunakan kelebihan DrawString yang mengambil persegi panjang target dan menambahkan StringFormat ke tengah di kedua arah. StringFormat tersedia sejak .Net 1.1 dan memang IDisposable, jadi kita harus membuang setiap yang kita buat, paling baik dalam klausa using..

Perhatikan bahwa untuk kontrol menggambar penggunaan TextRenderer dianjurkan tetapi hanya disertakan dengan .Net 2.0.

Perhatikan juga bahwa saya mengganti Brushes dengan SystemBrushes..

Juga: ComboBox saya tidak menempatkan teks di bagian Teksnya di kiri atas tetapi di kiri tengah. Mungkin kontrol .Net1.1 yang lama adalah pelakunya?

person TaW    schedule 13.04.2018
comment
Percaya atau tidak, StringFormat sebenarnya mengimplementasikan IDisposable. Pergilah. - person LarsTech; 13.04.2018
comment
Oke, saya yakin.. terima kasih telah melacak barang-barang saya ;-) - person TaW; 13.04.2018
comment
Saya tidak mengerti mengapa Anda mengatakan ini tidak menjawab pertanyaan OP. Selain itu, jika Anda menyetel DropDownStyle ke DropDownList, teks di bagian editor akan berada di tengah. Jadi, ada juga dua kemungkinan cara menyajikan konten. Saya pikir inilah yang diminta. - person Jimi; 13.04.2018
comment
Meskipun versi DropDownList adalah pengamatan yang bagus, (terima kasih untuk itu!) OP dengan jelas menunjukkan bidang teks yang dapat diedit. Otoh itu juga menampilkan dropdown yang tidak terpusat tetapi kodenya setidaknya tampaknya mencoba untuk memusatkan.. - person TaW; 13.04.2018