Avatar billede Lasse Novice
23. juni 2003 - 23:50 Der er 20 kommentarer og
2 løsninger

Forkortelse af path

Jeg har et listview hvori der er en kolonne kaldet file. Denne raekke indeholder stier til filer.

Nogen gange saa er stien laengere end der er plads til i selve kolonnen, og jeg har set at MS kommer udenom dette ved at cutte noget af kolonnen af. F.eks. hvis man nu har denne sti:

c:\Documents and settings\User name\Desktop\bla\bla
saa kunne denne f.eks blive cuttet ned til:
c:\Documents and settings\...\Desktop\bla\bla
eller mindre:
c:\Documents and ...\bla\bla

Hvordan laver man denne funktionalitet?

Jeg regner med at man som parametre til det der beregner dette, skal vaere font'en, stringen, og maks bredden.

Tak paa forhaand...
Avatar billede Peter Praktikant
24. juni 2003 - 00:35 #1
Uden at give dig selve koden vil mit forslag være:

Stiens navn er vel en String. Så du kan tage at checke længden af denne string, hvis den er over 25 tegn, så exploder du den og tager de første 12 tegn + ... + de sidste 10 tegn og imploder dette og gemmer det under det gamle stringnavn.
Hvis du skal bruge strengen senere til at kalde filen, så skal du nok lave noget med at beholde den oprindelige streng og lave en ny til brug i tabellen.

Dette vil ikke være svært at lave i C++, jeg er dog ikke så godt hjemme i syntaksen, så derfor har jeg ikke lavet noget kode.
Avatar billede Lasse Novice
24. juni 2003 - 01:47 #2
laengden af strengen er ikke godt nok, eftersom jeg ikke ved hvor stor fonten er. Jeg maa skulle bruge stoerrelsen paa strengen naar den bliver skrevet med en bestemt type font.

Faktisk troede jeg at denne funktion var saa esential, saa at koden var et sted paa nettet.
Avatar billede nielslbeck Nybegynder
24. juni 2003 - 08:09 #3
Tror ikke du skal regne med at finde koden nogen steder på nettet - og hvis du gør, vil det være lavet som petter78 skriver, da funktionen i de fleste programmer er implementeret på netop den måde.
Avatar billede nielslbeck Nybegynder
24. juni 2003 - 08:39 #4
Eller... på den anden side, så ville petter78's løsning være rimelig ubrugelig... hvem siger at filnavnet ikke er længere end 12 tegn? Hvis det er det, vil man ikke kunne se hele filnavnet, hvilket nok ikke ville være særlig smart.

Jeg har derfor lavet en anden løsning, hvor man altid kan se hele filnavnet, og så skærer den stien ned. Det giver følgende output:

- Hvis den fulde sti er mindre end den ønskede længde, returneres hele strengen.

- Uanset om der er plads til stien eller ej, vises hele filnavnet, med drevangivelse først. Eksempel med ønsket længde 15: c:\...\filnavn.txt

- I sidste tilfælde vises hele filnavnet og den del af stien som der er plads til indenfor den ønskede længde. Eksempel med ønsket længde 30: c:\windows\syste...\system.dll

Og her kommer koden:

public string MakeFit(string filename, int length) {
  if (filename.Length <= length)
    return filename;

  FileInfo fi = new FileInfo(filename);
  string seperator = "...\\";
  int pathLength = length - fi.Name.Length - seperator.Length >= seperator.Length ? length - fi.Name.Length - seperator.Length : 3;
  return filename.Substring(0, pathLength) + seperator + fi.Name;
}

Hvis du i stedet for ønsker at lave den så længden altid passer med fonten, bliver du nødt til at lave det så den fjerner et stykke af strengen, tjekker længden, fjerner et stykke af strengen, tjekker længden osv. Det vil altså blive en meget langsommere funktion, end ovenstående som har konstant udførselstid. Jeg ville derfor benytte ovenstående, hvis der er mange stier der skal kortes ned...
Avatar billede bennytordrup Nybegynder
24. juni 2003 - 09:02 #5
Du kan også bruge de API-funktioner, der er til formålet (PathCompactPath og PathCompactPathEx). Se evt. nedenstående:

using System.Windows.Forms;
using System.Drawing;

internal class PathEx
{
    [DllImport("shlwapi.dll", CharSet=CharSet.Auto)]
    public static bool PathCompactPath(IntPtr hDC, StringBuilder lpszPath,
uint dx);

    [DllImport("shlwapi.dll", CharSet=CharSet.Auto)]
    public static bool PathCompactPathEx(StringBuilder pszOut, String
pszSrc, uint cchMax, uint dwFlags);
}

private class MyForm : Form
{
    public static int Main
    {
        Application.Run(new MyForm());
        retrun 0;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        StringBuilder path = new
StringBuilder(@"C:\misc\misc\misc\misc\misc\misc");
        if(!PathEx.PathCompactPath(e.Graphics.GetHdc(), path, 64))
            throw new CWin32Exception();

        e.Graphics.DrawString(path.ToString(), new
Font(FontFamily.GenericSansSerif, 10.0f), new SolidBrush(Color.Black), 128,
128);
    }
}
Avatar billede bennytordrup Nybegynder
24. juni 2003 - 09:03 #6
Ovenstående kode er fundet i en nyhedsgruppe om C#
Avatar billede nielslbeck Nybegynder
24. juni 2003 - 09:07 #7
Så vil jeg nok stadig foretrække min egen løsning... det går ikke ligefrem hurtigt at skulle kalde over i en unmanaged dll...
Avatar billede bennytordrup Nybegynder
24. juni 2003 - 09:10 #8
nielslbeck>> Jeg har ikke oplevet hastighedsproblemer med at kalde unmanaged dll. API-funktionen PathAddBackslash er heller ikke implementeret i Path klassen. Jeg har prøvet med to implementeringer af den (en, hvor jeg selv tester på sidste tegn, og en, hvor jeg kalder direkte til PathAddBackslash i API). Der var ikke forskel at mærke på trods af *mange* kald til rutinen (i en opbygning af biblioteksstruktur i et TreeView).
Avatar billede Lasse Novice
24. juni 2003 - 17:19 #9
benny.tordrup >>

Jeg kan ikke se hvordan jeg kan faaet taget hoejde for at min font stoerrelse er kaempe stor f.eks.

nielslbeck>>

En endnu smartere maade ville vaere:

1) Jeg kender den font jeg arbejder med. Derfra ved jeg font hoejden i pixels(emsize). Det er nu bredden jeg er efter, men den findes let ved foelgende simple formel:
emsize * 3(bredde) / 4(hoejde). Dvs. at jeg nu ved bredden paa min font. Lad os sige at her er den 6.
2) Jeg ved ogsaa hvor plads jeg har ialt. F.eks. er det en label, saa er det bredden(- evt. offsets). Lad os sige at den er 200 her.
3) Nu kan jeg saa beregne hvor mange tegn der kan vaere maksimalt i min label:
makstegn = Floor(200 / 6)
4) kald din funktion
Dette ville ogsaa have en konstant eksekveringstid.
Avatar billede nielslbeck Nybegynder
24. juni 2003 - 18:23 #10
gooky>> Ja, det ville være smartere... men det kan bare ikke bruges, da alle tegn ikke er lige brede! Der er f.eks. forskel på hvor meget "H" og "i" fylder i bredden - i hvert fald ved de fleste skrifttyper...
Avatar billede Lasse Novice
24. juni 2003 - 18:32 #11
nielslbeck >>

yes, det har du ret i, men efter meget hurtig soegning, ser det ud til at det er maksimum bredden(forholdet er maks 3/4). Jeg har kun undersoegt det ved at gaa ind i Character Map, saa det kan godt vaere at det ikke er sandheden. Jeg bruger maks settings, hvilket kun betyder at det i hvert fald aldrig kommer ud over bredden.
Avatar billede nielslbeck Nybegynder
24. juni 2003 - 18:34 #12
Det er så rigtigt nok... Så hvis man kan leve med, at stierne kan komme til at fylde mindre end den maksimale bredde, vil det være kanon at regne ud hvor meget plads man har, og så bruge ovenstående metode til at korte stien ned...
Avatar billede Lasse Novice
24. juni 2003 - 18:37 #13
nielslbeck >>

Kan man maaske faa de API kald til at tage hoejde for fonten, for saa vil de jo vaere perfekte.
Avatar billede nielslbeck Nybegynder
24. juni 2003 - 18:44 #14
Tror jeg ikke du skal regne med... sjældent man ser et program som gør det på den måde...
Avatar billede Lasse Novice
24. juni 2003 - 18:47 #15
men den maa jo tage en font stoerrelse som standard naar den beregner... Men hvilken font er det. Hvis man viste det, saa kunne man tage forholdet mellem bredderne paa den font og den font man nu bruger.
Avatar billede nielslbeck Nybegynder
24. juni 2003 - 18:49 #16
Det kan man jo så ikke... Der er jo ikke nogen der siger, at fordi et "i" har en bredde i en font og en anden i en anden font, er forholdet mellem dem det samme som forholdet mellem "H" i de to fonte...
Avatar billede Lasse Novice
24. juni 2003 - 18:52 #17
nej, det kan du have ret i
Avatar billede bennytordrup Nybegynder
25. juni 2003 - 08:39 #18
API-kaldet tager højde for fonten via den hDC handle, der bliver overført via første parameter.

Fra Platform SDK:

PathCompactPath Function

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

Truncates a file path to fit within a given pixel width by replacing path components with ellipses.

Syntax

BOOL PathCompactPath(          HDC hDC,
    LPTSTR lpszPath,
    UINT dx
);
Parameters

hDC
[in] Handle to the device context used for font metrics.
lpszPath
[in, out] Pointer to a null-terminated string of length MAX_PATH that contains the path to be modified. On return, this buffer will contain the modified string.
dx
[in] Width, in pixels, within which the string will be forced to fit.
Return Value

Returns TRUE if the path was successfully compacted to the specified width. Returns FALSE on failure, or if the base portion of the path would not fit the specified width.

Remarks

This function uses the font currently selected in hDC to calculate the width of the text. This function will not compact the path beyond the base file name preceded by ellipses.
Avatar billede Lasse Novice
25. juni 2003 - 15:40 #19
det var ogsaa mit allerfoerste logiske bud, men da jeg proevede, gav det ikke det resultat. Det kan vaere at jeg har lavet lort i den, jeg proever lige igen.
Avatar billede Lasse Novice
26. juni 2003 - 18:29 #20
undskyld, jeg har lige haft travlt med noget andet.

Ok, en simpel test, der viser at det ikke helt fungerer efter de regler man gerne oenskede:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            System.Text.StringBuilder path = new System.Text.StringBuilder(@"C:\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc\misc.txt");
            try
            {
                //this.Font = new System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 20, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Pixel);
                System.IntPtr hdc = e.Graphics.GetHdc();
               
                bool k = PathEx.PathCompactPath(hdc, path, (uint)this.Width);
                System.Diagnostics.Debug.WriteLine(path);
                System.Diagnostics.Debug.WriteLine(this.Width);
                e.Graphics.ReleaseHdc(hdc);

                e.Graphics.DrawString(path.ToString(), this.Font, System.Drawing.Brushes.Green, 0.0F, 0.0F);
            }
            catch
            {
            }
            //base.OnPaint (e);
        }

Her bliver strengen meget kortere end selve kontrollen hvori denne onpaint er overriden(jeg har bare gjort det i formen). Proever man derimod at aendre paa fonten(som jeg har udkommenteret her), saa bliver strengen stoerrere end selve formen. Den bruger vist ikke DEN font som intern parameter i hdc'en. Har du en kommentar til det benny
Avatar billede Lasse Novice
26. juni 2003 - 19:11 #21
har fundet ud af at min udvidelse af nielsbecks forslag ikke fungerer...
Avatar billede Lasse Novice
26. juni 2003 - 20:11 #22
Man kan tage hoejde for fonten ved dette:

Erklaering i PathEx:
[System.Runtime.InteropServices.DllImport("gdi32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
    public extern static long SelectObject(System.IntPtr hdc, System.IntPtr hObject);

I OnPaint:
...
...
System.IntPtr hFont = this.Font.ToHfont();
PathEx.SelectObject(hdc, hFont);
PathEx.PathCompactPath(hdc, path, (uint)this.Width);
...
...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester